[练习][洛谷1613]倍增+Floyd 跑路

来源:互联网 发布:日历制作软件 编辑:程序博客网 时间:2024/06/06 17:48

题目背景
洛谷1613

题目描述
小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零。可是小A偏偏又有赖床的坏毛病。于是为了保住自己的工资,小A买了一个十分牛B的空间跑路器,每秒钟可以跑2^k千米(k是任意自然数)。当然,这个机器是用longint存的,所以总跑路长度不能超过maxlongint千米。小A的家到公司的路可以看做一个有向图,小A家为点1,公司为点n,每条边长度均为一千米。小A想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司。数据保证1到n至少有一条路径。

输入格式
第一行两个整数n,m,表示点的个数和边的个数。

接下来m行每行两个数字u,v,表示一条u到v的边。

输出格式
一行一个数字,表示到公司的最少秒数。

样例数据
输入

4 4
1 1
1 2
2 3
3 4

输出

1

备注
【样例说明】
1->1->2->3->4,总路径长度为4千米,直接使用一次跑路器即可。

【数据范围】

50%的数据满足最优解路径长度<=1000;

100%的数据满足n<=50,m<=10000,最优解路径长度<=maxlongint。

分析:刚刚看到这道题,嗯,求最短路?dijkstra、SPFA走你!诶?好像不对,这个2k速度是什么鬼???倍增?!好吧,删掉重来,想了半天,这个倍增怎么写,看看只有50个点,数据很小,干脆直接暴力循环好了。求完后,哎呀,无脑暴力就是爽,干脆最短路也直接用floyd好了。
(好吧,倍增部分的思维过程是瞎扯的,其实没想到竟然是暴力,参考了题解orz)

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;int getint(){    int sum=0,f=1;    char ch;    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());    if(ch=='-')    {        f=-1;        ch=getchar();    }    for(;isdigit(ch);ch=getchar())        sum=(sum<<3)+(sum<<1)+ch-48;    return sum*f;}int n,m,dis[55][55];bool mi[55][55][65];//mi[i][j][k]的意思是判断i到j是否存在一条长度为2^k的路径int main(){    freopen("run.in","r",stdin);    freopen("run.out","w",stdout);    int u,v;    n=getint(),m=getint();    for(int i=1;i<=n;++i)        for(int j=1;j<=n;++j)            dis[i][j]=1e9;//赋初值,直接memset都可以(之前以为longint是long long,赋成1e18了)    for(int i=1;i<=m;++i)    {        u=getint(),v=getint();        dis[u][v]=1;//记录路径值        mi[u][v][0]=true;//u、v相距2^0    }    for(int l=1;l<=64;++l)//由于总长度不超过maxlongint,所以2^32是足够了,但是就是因为理解错了longint的意思,所以写的2^64        for(int k=1;k<=n;++k)//因为用到floyd,我这里还想了想这三个for循环有没有顺序问题hhh,//这里只是枚举所有情况,不是求最短路,所以顺序随便(只要2的几次方在最外层就可以了)            for(int i=1;i<=n;++i)                for(int j=1;j<=n;++j)                    if(mi[i][k][l-1]&&mi[k][j][l-1])//如果存在两个2^(i-1)的路,那么两端点就相距2^i,即可以一次跳到,//相当于在这两个点间有一条距离位1的路(方便求最短路)                    {                        mi[i][j][l]=true;                        dis[i][j]=1;                    }    for(int k=1;k<=n;++k)//floyd        for(int i=1;i<=n;++i)            for(int j=1;j<=n;++j)                if(dis[i][j]>dis[i][k]+dis[k][j])                    dis[i][j]=dis[i][k]+dis[k][j];    cout<<dis[1][n]<<'\n';    return 0;}

本题结。

原创粉丝点击