1. 程式人生 > >「2017 山東一輪集訓 Day6」重建 - dp

「2017 山東一輪集訓 Day6」重建 - dp

題目大意:
給一張無向帶權連通圖,和一些關鍵點,求一個最大的非負整數c,使得每條邊的邊權加上c之後,s到t的最短路等於s到t只經過關鍵點的最短路。
題解:觀察到s到t的最短路是一個關於邊數的分段函式,令f[x,i]表示從s出發走到x經過恰好i條邊的最短路,g為經過關鍵點的陣列。
那麼分別意會出這兩個分段函式後,就是求一個x,使得兩個函式在此處取值相同。
注意到g[t,i]>=f[t,i],也就是當有某個位置x成為答案時,一定有某個i,設第i段的有效範圍的交集是[L,R],則 x

[ L , R ] x\in[L,R] ,並且此時g[t,i]=f[t,i]。
那麼列舉這樣的i,計算相應的R,然後對所有的R取個max即可。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++) #define Rep(i,v) rep(i,0,(int)v.size()-1) #define lint long long #define db double #define pb push_back #define mp make_pair #define fir first #define sec second #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl
using namespace std; typedef pair<int,int> pii; typedef set<int>::iterator sit; inline int inn() { int x,ch;while((ch=gc)<'0'||ch>'9'); x=ch^'0';while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; } const int N=1010,M=10010; const lint INF=LLONG_MAX/10; struct edges{ int to,pre,wgt; }e[M<<1];int h[N],etop; lint f[N][M],g[N][M];int imp[N]; inline int add_edge(int u,int v,int w) { return e[++etop].to=v,e[etop].wgt=w,e[etop].pre=h[u],h[u]=etop; } inline int getdis(lint (*f)[M],int n,int s) { rep(i,1,n) rep(j,0,n) f[i][j]=INF;f[s][0]=0; rep(i,1,n) rep(x,1,n) if(imp[x]) for(int t=h[x],y;t;t=e[t].pre) if(imp[y=e[t].to]) f[x][i]=min(f[x][i],f[y][i-1]+e[t].wgt); return 0; } inline lint getinter(lint *f,int a,int b,int sqz) { if(a>b) swap(a,b); if(f[a]<f[b]) return -1; if(f[a]==f[b]) return 0; if(f[a]==INF) return INF; lint x=f[a]-f[b],y=b-a; if(sqz) return (x-1)/y+1; return x/y; } inline int getrange(lint *f,int m,int p,lint &L,lint &R) { L=-1,R=INF; rep(i,1,p-1) R=min(R,getinter(f,p,i,0));//xiaquzheng rep(i,p+1,m) L=max(L,getinter(f,p,i,1));//shangquzheng return 0; } int main() { for(int T=inn();T;T--) { int n=inn(),m=inn(),s=inn(),t=inn();lint ans=-1; memset(h,0,sizeof(int)*(n+1)),etop=0;int x,y,w; rep(i,1,m) x=inn(),y=inn(),w=inn(),add_edge(x,y,w),add_edge(y,x,w); rep(i,1,n) imp[i]=1;getdis(f,n,s); rep(i,1,n) imp[i]=0;int k=inn(); rep(i,1,k) imp[inn()]=1;getdis(g,n,s); rep(i,0,n) if(f[t][i]==g[t][i]&&f[t][i]<INF) { lint l,r;getrange(f[t],n,i,l,r); lint L,R;getrange(g[t],n,i,L,R); L=max(L,l),R=min(R,r); if(L<=R) ans=max(ans,R); if(ans==INF) break; } if(ans<0) printf("Impossible\n"); else if(ans==INF) printf("Infinity\n"); else printf("%lld\n",ans); } return 0; }