【洛谷1613】跑路(倍增+最短路)

点此看题面

大致题意:\(A\)要从\(1\)号节点到\(n\)号节点,已知他每个单位时间可以跑\(2^k\)千米,求他最少需要多少个单位时间。

预处理

由于数据范围较小,我们可以先大力预处理。

首先,将题目中给出的边边权初始化为\(0\)

若从一点出发,到两点皆有一条边权为\(w-1\)的边,就将这两点之间连一条边权为\(k\)的边。

这样重复\(n\)次,就能保证所有该连的边都连好了。

\(Dijkstra\)跑最短路

然后,我们可以在这张图上跑最短路了。

注意,无论边权为多少,每条边长度皆为\(1\)

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 50
#define Log 50
#define INF 1e9
#define add(x,y,z) !Ex[x][y][z]&&(e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].v=z,Ex[x][y][z]=1)
using namespace std;
int n,m,ee=0,lnk[N+5],Ex[N+5][N+5][Log+5];struct edge {int to,nxt,v;}e[N*N*Log+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		char c,*A,*B,FI[FS];
	public:
		I FastIO() {A=B=FI;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
class Dijkstra
{
	private:
		#define mp make_pair
		#define fir first
		#define sec second
		int dis[N+5],vis[N+5];typedef pair<int,int> Pr;
		priority_queue<Pr,vector<Pr>,greater<Pr> > q;
	public:
		I void Init()//初始化
		{
			for(RI w=1,i,j,k;w<=n;++w) for(i=1;i<=n;++i) for(j=1;j<=n;++j) 
				for(k=1;k<=n;++k) Ex[i][j][w-1]&&Ex[j][k][w-1]&&add(i,k,w);
		}
		I int GetAns(CI s,CI t)//最短路
		{
			RI i;Pr k;for(i=1;i<=n;++i) dis[i]=INF;dis[s]=0,q.push(mp(0,s));
			W(!q.empty())
			{
				W(!q.empty()&&vis[q.top().sec]) q.pop();if(q.empty()) break;
				for(vis[(k=q.top()).sec]=1,q.pop(),i=lnk[k.sec];i;i=e[i].nxt)
					k.fir+1<dis[e[i].to]&&(q.push(mp(dis[e[i].to]=k.fir+1,e[i].to)),0);
			}return dis[t];
		}
}S;
int main()
{
    for(RI i=(F.read(n,m),1),x,y;i<=m;++i) F.read(x,y),add(x,y,0);//初始化边权为0
    return S.Init(),printf("%d",S.GetAns(1,n)),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1613.html