【搜索or图论】【CQBZOJ 2443】考验

来源:互联网 发布:网络运营职责 编辑:程序博客网 时间:2024/05/17 22:31

问题 B(2443): 考验
时间限制: 1 Sec 内存限制: 128 MB

题目描述
【题目背景】
话说高考研讨会上有许多志愿者,其中有许多女生,性格开朗、活泼的 zn 很快就
与这 些女生打成一片,把 z 同学晾在了一边。现场人很多,小 z 一转眼发现找不
到了 zn 一伙人 了,肿么办,计划赶不上变化啊,小 z 找到了志愿者总管:一个带
着小红帽的死胖子,死胖 子说了:想知道她在哪啊,听说你是 410 的,听说 410
都是些牛逼人啊,我得考考你。
小 z 心想:考考考,我靠你 LM 啊,MD,要不是 LZ 有急事,早把你办了~!~
【题目描述】
死胖子出题了,咱们现在处于1区域,zn处于2区域,一共有n个区域,有一些路连接着两个区域,路有长度,死胖子规定一条从1到2的路径的权值为这条路上每条路长度的最大公约数,他叫你求出所有能从区域1到2的路径的权值的最小公倍数(路径上的点最多经过一次)

输入
第一行:n
接下来是一个nn的矩阵,i 行 j 列的值代表从 i 区域到 j 区域的路径长度,若不连通,则为 0

输出
所求的最小公倍数

样例输入
4
0 0 3 16
0 0 9 6
3 9 0 0
16 6 0 0

样例输出
6

【数据范围】

2n25
1<<2000
Hint:不用高精度哦


这道题的第一种做法是大暴力。。。也就是搜索。
从1号节点找到到第2号节点的每一条路,然后边走边算GCD,走完后统计LCM就行了。

当然,这玩意是玄学复杂度,对于2n25,还是够了。
但,我们不要这么挫的做法。我眨眼一看1<<2000
果断枚举答案的因数i,如果可以找到一条路从1到2,并且路上的每一条边权都为i的倍数,那么自然ans=ans/gcd(ans,i)i
check(i)可以用BFS,保证访问过的点不再访问对检验结果没有影响。
时间复杂度为O(nnmaxval)

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;#define MAXN 25#define MAXM 2000#define INF 0x3f3f3f3ftypedef long long int LL;int getint(){    int rn=0;    char c=getchar();    while(c<'0'||'9'<c)        c=getchar();    while('0'<=c&&c<='9')    {        rn=rn*10+c-'0';        c=getchar();    }    return rn;}int G[MAXN+10][MAXN+10];int N,M;LL gcd(LL a,LL b){    if(!b)return a;    else return gcd(b,a%b);}queue<int>que;bool vis[MAXN+10];bool check(int val){    memset(vis,0,sizeof(vis));    while(!que.empty())que.pop();    que.push(1);    vis[1]=1;    int now;    while(!que.empty())    {        now=que.front();que.pop();        if(now==2)return true;        for(int i=1;i<=N;++i)            if(!vis[i]&&G[now][i]&&G[now][i]%val==0)            {                que.push(i);                vis[i]=1;            }    }    return false;}int main(){    //freopen("test2.in","r",stdin);    N=getint(),M=0;    int i,j;    for(i=1;i<=N;++i)        for(j=1;j<=N;++j)            M=max(M,G[i][j]=getint());    if(check(1)==0)    {        puts("0");        return 0;    }    LL ans=1;    for(i=M;i>=2;--i)        if(check(i))ans=ans/gcd(ans,i)*i;    printf("%lld\n",ans);}/*40 0 5 250 0 15 55 15 0 025 5 0 040 0 0 250 0 15 00 15 0 025 0 0 0*/
2 0