bzoj 2330: [SCOI2011]糖果 差分約束系統
阿新 • • 發佈:2019-01-25
題意:幼兒園裡有N個小朋友,lxhgww老師現在想要給這些小朋友們分配糖果,要求每個小朋友都要分到糖果。但是小朋友們也有嫉妒心,總是會提出一些要求,比如小明不希望小紅分到的糖果比他的多,於是在分配糖果的時候,lxhgww需要滿足小朋友們的K個要求。幼兒園的糖果總是有限的,lxhgww想知道他至少需要準備多少個糖果,才能使得每個小朋友都能夠分到糖果,並且滿足小朋友們所有的要求。
分析:很明顯的差分約束系統。
由於是求最小值,所以就要把所有不等式都轉換成x-y>=k的形式然後連一條y->x權值為k的邊。
後四個操作都很簡單,關鍵是第一個操作。
那麼我們就可以把A=B轉換成A-B>=0且B-A>=0然後跑最長路最後統計就好啦。
還有就是判斷負權(最短路)或正權(最長路)迴路的問題,若一個點被鬆弛了n次以上則為有迴路。
有一個很神奇的地方就是加起點到所有點的邊的時候要倒著加不然就會T(我也不造為毛)
程式碼:
const
maxn=100005; maxm=100005; var state,d,last,time:array[0..maxn] of longint; v:array[0..maxn] of boolean; side:array[1..maxm*3] of record x,y,z,next:longint; end; n,m,e:longint; procedure add(x,y,z:longint); begin inc(e); side[e].x:=x; side[e].y:=y; side[e].z:=z; side[e].next:=last[x]; last[x]:=e; end; procedure init; var x,y,z,i:longint; begin readln(n,m); for i:=1 to m do begin readln(z,x,y); case z of 1:begin add(x,y,0); add(y,x,0); end; 2:add(x,y,1); 3:add(y,x,0); 4:add(y,x,1); 5:add(x,y,0); end; end; for i:=n downto 1 do add(0,i,1); end; procedure spfa; var head,tail,i,u:longint; ans:int64; begin for i:=1 to e do with side[i] do if (x=y)and(z>0) then begin writeln(-1); exit; end; head:=0; tail:=1; state[1]:=0; time[0]:=1; fillchar(v,sizeof(v),true); v[0]:=false; repeat inc(head); if head>n+1 then head:=1; u:=state[head]; i:=last[u]; while i>0 do with side[i] do begin if d[x]+z>d[y] then begin inc(time[y]); if time[y]>n then begin writeln(-1); exit; end; d[y]:=d[x]+z; if v[y] then begin v[y]:=false; inc(tail); if tail>n+1 then tail:=1; state[tail]:=y; end; end; i:=next; end; v[u]:=true; until head=tail; ans:=0; for i:=1 to n do ans:=ans+d[i]; writeln(ans); end; begin init; spfa; end.