Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
解题报告题意: 给出一张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: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator