正解:倍增+图论
解题报告:
话说这题是真滴很妙啊,,,大概港下QwQ
首先看懂这道题,它是说,只要是1<<k的都能1s跑过,而且每条边的长度都是1,就是说一秒可以跑过1<<k条边
于是就可以先预处理出只用跑1s的点之间连上边,然后就变成最短路问题辣!
至于怎么预处理只用跑1s的点,就开一个bool数组f[i][j][k]表示i到j能否在2<<k内跑过去,然后转移就很好想了嘛,如果f[i][p][k]&&f[p][j][k]那就能转移到f[i][j][k+1]
话说看到这个转移,可以发现是枚举三个点嘛,于是想到Floyd,于是就没啦!
(,,,听说可以用spfa!好神仙的样子!想学!QAQ!
然后关于最后的求最短路,,,看到题解里都是Floyd或者spfa什么的,,,但是我jio得它都说了每条边长度为1了难道不是暗示用bfs?反正我用的bfsQAQ我我我我也不清楚复杂度QAQ
(还有个玄学事件我要记录下,,,是这样的,本来它是说M<=10000,但是我看N<=50就想着肯定是有重边,我就判了下重边什么的edge数组就开得不大
然后就一直RERERE,我加加加空间加到极大才过得去,,,但我jio得不应该啊我明明特判的重边的?QAQ?
#include<bits/stdc++.h> using namespace std; #define ll int #define mp make_pair #define rp(i,x,y) for(register ll i=x;i<=y;++i) const ll N=60,M=500000+100; ll n,m,head[N],cnt; bool gg[N][N][65],gdgs=1,vis[N],rd[N][N]; struct ed{ll to,nxt;}edge[M<<2]; inline ll read() { register char ch=getchar();register ll x=0;register bool y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar(); if(ch=='-')ch=getchar(),y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar(); return y?x:-x; } inline void ad(int x,int y){edge[++cnt].to=y;edge[cnt].nxt=head[x];head[x]=cnt;} inline void bfs() { queue< pair<ll,ll> >Q;Q.push(mp(1,0));vis[1]=1; while(gdgs) { ll nw=Q.front().first;ll tm=Q.front().second;Q.pop(); if(nw==n){printf("%d",tm);return;} for(register ll i=head[nw];i;i=edge[i].nxt) {if(vis[edge[i].to])continue;Q.push(mp(edge[i].to,tm+1));vis[edge[i].to]=1;} } } int main() { // freopen("1613.in","r",stdin); n=read();m=read();rp(i,1,m){ll x=read(),y=read();gg[x][y][0]=1;ad(x,y);} rp(p,1,64) rp(k,1,n) rp(i,1,n) rp(j,1,n)if(gg[i][k][p-1] && gg[k][j][p-1])gg[i][j][p]=1,ad(i,j); bfs(); return 0; }