Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

解题报告

Posted by yousiki at 2016-07-25 09:41:56 on Problem 2132
题意:
给出一张N*N的邻接矩阵。请你求出所有从1点到2点的路径上的边权公约数的最小公倍数。
呃~~~,我们再来理一遍……
就是从1到2有若干条不同的路径,对于每一条路径,其又包含若干条边。
我们要求出这一条路径上所有边的边权的最大公约数,然后对所有路径求出来的最大公约数求最小公倍数。

分析:
数据很水,很水,很水……
如果不想动脑子,可以直接DFS,或者BFS,随你啦。也就是说,这题暴力可解。
看到有前辈提出了一个强力的剪枝,据说轻松0MS——如果当前DFS到的路径上的最大公约数是当前已知解的约数,就可以直接BREAK了。嗯嗯,很有道理呢~~~这个剪枝的正确性也是因为这道题只询问1->2的答案,所以,还是有限制的。
于是,我认为更为优秀的做法(至少看起来带点智商了)是Floyd。
准确的讲,是把Floyd的思路运用到这题上。
我把原本的G[][]表示i->j之间最短路径,改为i->j的所有路径的局部答案。嗯,不清楚怎么描述。看代码体会吧,这都是满满的数学。

代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const signed N = 30;
inline int gcd(int x, int y) {
	if (x < y)swap(x, y);
	int tmp;
	while (y != 0) {
		tmp = x%y;
		x = y;
		y = tmp;
	}
	return x;
}
int n, G[N][N];
signed main(void) {
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%lld", &G[i][j]);
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				if (G[i][k] && G[k][j]) {
					int tmp = gcd(G[i][k], G[k][j]);
					if (G[i][j] == 0)G[i][j] = 1;
					G[i][j] = tmp*G[i][j] / gcd(G[i][j], tmp);
				}
	printf("%lld\n", G[1][2]);
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator