P1948 [USACO08JAN]Telephone Lines S 题解 Link Solve Code

P1948 [USACO08JAN]Telephone Lines S

Solve

一道比较经典的分层图最短路,(F[x][p])表示从(1)走到(x),其中第(p)条路径免费,剩下路径的最大值

转移方程也很简单,如果有一条从(x)(y)的边,用(max[x][p],cost(x,y)))来更新(F[y][p])表示不用免费的

(F[x][p])更新(F[y][p+1]),表示这条边用免费的

然后用(SPFA)直接刷就好了,貌似没有卡(SPFA)

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005,maxp=10005,maxe=20005;
int N,P,K;
int lnk[maxn],nxt[maxe],son[maxe],cnt,w[maxe],INF;
int F[maxn][maxn],vis[maxn][maxn];
struct AS{
	int x,p;
}Q[maxn*maxn];
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
inline void add_e(int x,int y,int z){son[++cnt]=y;w[cnt]=z;nxt[cnt]=lnk[x];lnk[x]=cnt;}
void SPFA(){
	int hed=0,til=1;Q[til]=(AS){1,0};
	memset(F,63,sizeof F);INF=F[0][0];F[1][0]=0;
	while(hed!=til){
		hed=(hed+1)%(maxn*maxn);vis[Q[hed].x][Q[hed].p]=0;
		for(int j=lnk[Q[hed].x];j;j=nxt[j]){
			if(max(F[Q[hed].x][Q[hed].p],w[j])<F[son[j]][Q[hed].p]){
				F[son[j]][Q[hed].p]=max(F[Q[hed].x][Q[hed].p],w[j]);
				if(!vis[son[j]][Q[hed].p]){
					til=(til+1)%(maxn*maxn);Q[til]=(AS){son[j],Q[hed].p};vis[son[j]][Q[hed].p]=1;
					int now=(hed+1)%maxn;if(F[Q[now].x][Q[now].p]>F[Q[til].x][Q[til].p])swap(Q[now],Q[til]);
				}
			}
			if(Q[hed].p<=K&&F[Q[hed].x][Q[hed].p]<F[son[j]][Q[hed].p+1]){
				F[son[j]][Q[hed].p+1]=F[Q[hed].x][Q[hed].p];
				if(!vis[son[j]][Q[hed].p+1]){
					til=(til+1)%(maxn*maxn);Q[til]=(AS){son[j],Q[hed].p+1};vis[son[j]][Q[hed].p+1]=1;
					int now=(hed+1)%maxn;if(F[Q[now].x][Q[now].p]>F[Q[til].x][Q[til].p])swap(Q[now],Q[til]);
				}
			}
		}
	}
	return ;
}
int main(){
	freopen("P1948.in","r",stdin);
	freopen("P1948.out","w",stdout);
	N=read();P=read();K=read();
	for(int i=1;i<=P;i++){
		int x=read(),y=read(),z=read();
		add_e(x,y,z);add_e(y,x,z);
	}
	SPFA();
	printf("%d
",F[N][K]^INF?F[N][K]:-1);
	return 0;
}