BZOJ2763: [JLOI2011]飞行路线
【传送门:BZOJ2763】
简要题意:
给出n个点(编号为0~n-1),m条双向边,每条边都有权值,每经过边都要花该边的权值的费用,但是可以免费走k条边,求出从起点到终点的最少花费
题解:
SPFA,但要在list中添加一个变量为c,表示使用了多少次免费的机会,然后用二维数组f来记录答案,f[i][j]表示到第i个点用j次免费机会的最少费用
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; struct node { int x,y,d,next; }a[110000];int len,last[51000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int f[110000][11]; bool v[110000][11]; int n,m,kk;int st,ed; int list[110000][2]; void spfa() { int head=1,tail=2; memset(list,0,sizeof(list)); list[1][0]=st;list[1][1]=0; while(head!=tail) { int x=list[head][0],c=list[head][1]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(f[x][c]+a[k].d<f[y][c]) { f[y][c]=f[x][c]+a[k].d; if(v[y][c]==false) { v[y][c]=true; list[tail][0]=y; list[tail][1]=c; tail++;if(tail==100000+1) tail=1; } } if(f[x][c]<f[y][c+1]&&c<kk) { f[y][c+1]=f[x][c]; if(v[y][c+1]==false) { v[y][c+1]=true; list[tail][0]=y; list[tail][1]=c+1; tail++;if(tail==100000+1) tail=1; } } } head++;if(head==100000+1) head=1; v[x][c]=false; } } int main() { scanf("%d%d%d",&n,&m,&kk); scanf("%d%d",&st,&ed); for(int i=1;i<=m;i++) { int x,y,d; scanf("%d%d%d",&x,&y,&d); ins(x,y,d);ins(y,x,d); } for(int i=0;i<=n;i++) for(int j=0;j<=kk;j++) f[i][j]=999999999; memset(v,false,sizeof(v));v[st][0]=true; f[st][0]=0; spfa(); int mmin=999999999; for(int i=0;i<=kk;i++) mmin=min(f[ed][i],mmin); printf("%d\n",mmin); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚