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;
}