【GDOI 2016 Day2】第一題 SigemaGO
阿新 • • 發佈:2018-05-12
一次 img 分析 const using sin log str n+1
題目
分析
拆點連邊+spfa。
首先把圖分成2lim+1層,也就是每個點拆成2lim+1個點。
如果a和b之間、b和c有一條有向邊,那麽連邊(k,a)-->(k+1,b),(k+1,b)-->(k+2,c)(k=1、3、5、···、2lim+1,是當前點所在的層數),這兩條邊的權值和是l。也就是說當走了(k,a)-->(k+1,b)-->(k+2,c)這條路線時,就是抄了一次近道。
註意:在spfa中,當走到的點在第2、4、6、···、2lim層時,就只能往上走,因為當前點一定在抄近道的過程中。
#include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> const int maxlongint=2147483647; using namespace std; int next[800000],last[800000],to[800000],dis[13][200000],n,m,lim,l,tot,v[800000],ans,d[10000000][2]; bool bz[200000]; int bj(int x,int y,int z) { next[++tot]=last[x]; last[x]=tot; to[tot]=y; v[tot]=z; } int spfa() { int i,j,head=0,tail=1,k; d[1][0]=0; d[1][1]=1; dis[0][1]=0; while(head<tail) { k=++head; bz[d[k][0]*n+d[k][1]]=true; for(i=last[d[k][1]+n*d[k][0]];i;i=next[i]) { j=to[i]; int x=(j-1)/n; if(dis[x][(j-1)%n+1]>dis[d[k][0]][d[k][1]]+v[i]) { dis[x][(j-1)%n+1]=dis[d[k][0]][d[k][1]]+v[i]; if(bz[j]) { bz[j]=false; d[++tail][0]=x; d[tail][1]=(j-1)%n+1; } } } } } int main() { freopen("sigemago.in","r",stdin); freopen("sigemago.out","w",stdout); scanf("%d%d%d%d",&n,&m,&l,&lim); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); for(int j=1;j<=lim+1;j++) { bj(x+n*(j*2-2),y+n*(j*2-2),z); } for(int j=1;j<=lim*2;j++) { bj(x+n*(j-1),y+n*j,l*(j%2)); } } memset(dis,60,sizeof(dis)); memset(bz,true,sizeof(bz)); spfa(); ans=maxlongint; for(int i=1;i<=lim+1;i++) { if(ans>dis[i*2-2][n]) ans=dis[i*2-2][n]; } if(ans>=dis[0][0]) printf("-1\n"); else printf("%d\n",ans); }
【GDOI 2016 Day2】第一題 SigemaGO