编号中的数学_KEY

题目描述

从美国州际高速公路建筑者那里,奶牛们引进了一种路径编号系统,来给牧场之间的道路编号。他们已经把 N(1<=N<=25)个牧场,用 1 到 N 的整数编号。现在他们需要将牧场间的道路也编上不同的编号,编号可以从 1 到 2000.如:I9 和 I16。看下面一个例子,牧场编号为 1,2,3,4,道路编号为 I3,I6,I9,I16。贝茜喜欢从牧场 1 散步到牧场 2,在每次散步中,她从不经过同一个牧场两次或两次以上,所以,在上面的地图中,可能 的路径只有 1-4-2 和 1-3-2。在最近的几年中,贝茜已经具有了惊人的数学功底。所以,现在她想练习练习,在每次散步中,她记录下她所经过的道路的最大公约数。例如,在路径 1-4-2 中,她经过了 I16 和I6,它们的最大公约数是 2.她每天尝试一种不同的走法,在走完所有路径之后,她将所有的最大公约数集中起来。计算出它们的最小公倍数。例如:在上面例子中两个最大公约数分别是 2 和 3,所以最小公倍数是 6.对于很大的地图,贝茜要走完所有的路径是很累的。但是,她仍然想知道那个最小公倍数。请你帮助她。

输入格式

第 1 行输入 N。接下来 N 行,输入一个邻接矩阵,第 I 行第 J 列表示从 I 到 J 的道路的编号。如果 I 到 J 没有道路相连,用 0 表示。

输出格式

一个整数表示所有从 1 到 2 的路径的最大公约数的最小公倍数。这个数不超过 100 位。

输入样例

4

0 0 3 16

0 0 9 6

3 9 0 0

16 6 0 0

输出样例

6

 

看这个数据范围,就知道是DFS,但是数据稍稍有点大。

定义DFS(x,y),表示到第x个点,最大公因数为y。

对于这个DFS函数,我们可以加一个很强力的最优性剪枝。

如果当前的ans(最小公倍数),取p=gcd(map[x][i],y),如果ans%p==0就return。

可以这样想,如果ans%p==0,那么之后无论如何gcd也不能使ans改变。

code

#include <bits/stdc++.h>
using namespace std;
long long n,a[30][30],t[30];
long long ans=1,w;
long long gcd(long long x,long long y){return !y?x:gcd(y,x%y);}
void dfs(int x,int y){
    if(x==2){long long p=gcd(y,ans);ans*=y;ans/=p;return ;}
        for(int i=1;i<=n;i++){
            if(a[x][i]&&!t[i]){
                long long o=a[x][i],q=y;
                if(o<q)swap(o,q);
                long long p=gcd(o,q);
                if(ans%p)t[i]=1,dfs(i,p),t[i]=0;
            }
        }
}
int main(void){
    scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)scanf("%lld",&a[i][j]);
        }
    t[1]=1;
        for(int i=1;i<=n;i++){
            if(a[1][i])t[i]=1,dfs(i,a[1][i]),t[i]=0;
        }
    printf("%lld",ans);
    return 0;
}

 

posted @ 2017-09-25 19:16  Cptraser  阅读(372)  评论(0编辑  收藏  举报