加加減減
加加減減(pands.pas/c/cpp)
【題目背景】
話說zyk又雙叒叕在A圖論的題目了!!!
【問題描述】
zyk手裏有若幹幅有向圖,每條邊有個權值。你可以在這幅圖上操作若幹次(也是醉了),每次可以選擇一個節點u和一個整數d,把以u為起點的邊的權值增加d,把以u為終點的邊的權值減小d(難怪叫加加減減)。然而,zyk卻想讓所有邊權的最小值為正且盡量大。
【輸入文件】
輸入包含若幹組數據。每組數據第一行為兩個整數n和m(n≤500,m≤700),即點和邊的個數。以下m行每行三個整數u,v,w,即一條起點為u,終點為v,權值為w的邊(1≤u,v≤n,-10000≤w≤10000)。
【輸出文件】
對於每組數據,輸出邊權最小值的最大值。如果無法讓所有邊權都為正,輸出“No Solution”;如果最小邊權的最大值可以任意大,輸出“Infinite”。
【輸入樣例】
2 1
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1
【輸出樣例】
Infinite
Infinite
3
1
首先,我們應該註意到,結果與操作的順序是無關的。所以,對於同一個節點,對於它的多次操作,可以合並。那麽我們令sum(k)為作用在u上的所有權值之和。這樣,我們的目標就是求出min(sum(i))(i=1,n)。而題目中最小值最大又使我們自然而然想到二分。枚舉一個low,使問題變成操作完後能否使每條邊權值不小於low。對於邊a→b,在操作完後它的權值為w(a,b)+sum(a)-sum(b)。因此對於每條邊,都可以列出一個不等式w(a,b)+sum(a)-sum(b)≥low,移項得sum(b)<=sum(a)+w(a,b)-x。顯然,我們得到一個查分約束系統。並且這個差分約數系統轉化為圖論的話應該是眾多個裏面挑最小的。所以應轉為最短路問題。所以更新的那句話就變為if (sum(b)>sum(a)+w(a,b)-x) ......。當然,還有特殊情況,即No Solution和Infinite。
對於Infinite的情況:
判斷spfa(最大邊權+1)是不是真值。
因為當low=最大邊權時,所有邊的邊權都得到了增加,說明一個問題——按照這樣的操作繼續下去,最小邊權肯定還是增加的,所以可以一直這樣操作下去,最小邊權也就無窮大了。
對於No Sulotion的情況:
判斷spfa(1)是不是假值。
由於最小邊權要大於0,且為整數,所以至少唯一。如果1都達不到,就無解了。但是怎麽判斷這個查分約束系統無解?可以畫一個圖,例如:
x1<=x4,x2<=x1+3,x3<=x1-1,x3<=x2-2,x4<=x3-2(見下)
整理後發現部分不等式矛盾:x1<=x4+0,x3<=x1-1,x4<=x3-2(見下)
實質就是出現了負權回路。或者就根據這個例子分析,又前兩個不等式得x3<=x4-1。而後又出現x3>=x4+2。這兩個不等式沒有解集。只有最後一個不等式至少變為x4<=x3+1時才有集解(即x3>=x4-1,得x3=x4-1),此時,三條邊權值和為0-1+1=0。而剛才權值和為0-1-2=-3<0,可見,如果不等式組無解,則spfa(low)=false。
如果並不是特殊情況——直接二分得出答案。
1 #include<cstdio> 2 #include<cstring> 3View Code#include<algorithm> 4 using namespace std; 5 const int maxn=505,maxe=705,maxv=505; 6 int n,m,h,t,son[maxe],w[maxe],nxt[maxe],lnk[maxn],tot; 7 int q[maxv],d[maxn],ins[maxn]; 8 bool v[maxn]; 9 inline int read(){ 10 int x=0,f=1; char ch=getchar(); 11 while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-f; ch=getchar();} 12 while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); 13 return x*f; 14 } 15 void add(int x,int y,int z){ 16 nxt[++tot]=lnk[x],son[tot]=y,w[tot]=z,lnk[x]=tot; 17 } 18 bool spfa(int low){ 19 memset(q,0,sizeof q); 20 memset(d,63,sizeof d); 21 memset(v,0,sizeof v); 22 memset(ins,0,sizeof ins); 23 h=0,t=0; 24 for (int i=1; i<=n; i++) q[++t]=i,d[i]=0,v[i]=1,ins[i]++; 25 while (h!=t){ 26 h=(h+1)%maxv; v[q[h]]=0; 27 for (int j=lnk[q[h]]; j; j=nxt[j]){ 28 if (d[son[j]]>d[q[h]]+w[j]-low){ 29 d[son[j]]=d[q[h]]+w[j]-low; 30 if (!v[son[j]]){ 31 v[son[j]]=1,t=(t+1)%maxv,q[t]=son[j],ins[son[j]]++; 32 if (ins[son[j]]>n) return 0; 33 if (d[q[t]]<d[q[(h+1)%maxv]]) swap(q[t],q[(h+1)%maxv]); 34 } 35 } 36 } 37 } 38 return 1; 39 } 40 int main(){ 41 while (~scanf("%d%d",&n,&m)){ 42 int L=1,R=-(1<<30),ans=0; 43 tot=0; 44 memset(lnk,0,sizeof lnk); 45 memset(nxt,0,sizeof nxt); 46 for (int i=1; i<=m; i++){ 47 int x=read(),y=read(),z=read(); 48 add(x,y,z),R=max(R,z); 49 } 50 if (spfa(R+1)){ 51 puts("Infinite"); continue; 52 }else 53 if (!spfa(L)){ 54 puts("No Solution"); continue; 55 } 56 while (L<=R){ 57 int mid=(L+R)>>1; 58 if (spfa(mid)) ans=mid,L=mid+1; else R=mid-1; 59 } 60 printf("%d\n",ans); 61 } 62 return 0; 63 }
加加減減