【以前的空间】网络流合集
wikioi1034 家園
這是一道神奇的網(wǎng)絡(luò)流。具體詳細(xì)的題解以及代碼可以去Orz這個(gè)大神的博客。
傳送門:http://blog.csdn.net/lytning/article/details/23034379
??簡(jiǎn)單地說(shuō),就是要建立一個(gè)模型,就是把每個(gè)點(diǎn)(包括地球和月球)都分成無(wú)數(shù)多個(gè)點(diǎn)……比如第j個(gè)時(shí)刻的地球,就用地球i號(hào)表示,第i個(gè)中轉(zhuǎn)站就用i中轉(zhuǎn)站j表示。(處理是把月球-1自動(dòng)改為n+1吧)。把飛船看成是邊。然后就是神奇的跑一遍sap看是否能運(yùn)那么多人,不行再擴(kuò)展一層節(jié)點(diǎn)在跑一遍……orz語(yǔ)言能力不好還是去看上面那個(gè)大神的博客吧。最后把數(shù)組開(kāi)大!把記錄邊的數(shù)組開(kāi)到很大很大……不然就和我一樣wa了好多好多次……或者把time控制小一點(diǎn)……比如等于100是就不要找了根本找不到的,這樣時(shí)間差不多就剩下100ms(time為200要跑700ms)……
typearr=recordtoward,cap,next:longint;end;varedge:array[0..100000]of arr;d,num,first,cur,h:array[0..5000]of longint;c:array[0..50,0..10000]of longint;ss,tot,sum,st,s,t,i,j,k,n,m,kk,time,flow,leftk:longint;function cal(i,j:longint):longint;beginexit((n*2)*j+i+2);end;function min(x,y:longint):longint;beginif x>y then exit(y); exit(x);end;procedure add(i,j,k:longint);beginedge[tot].toward:=j;edge[tot].cap:=k;edge[tot].next:=first[i];first[i]:=tot; inc(tot);end;procedure addedge(i,j,k:longint);beginadd(i,j,k); add(j,i,0);end;function sap(v,flow:longint):longint;varrec,ret,i,j:longint;beginif v=st then exit(flow);rec:=0;i:=cur[v];while i<>-1 do beginj:=edge[i].toward;if (edge[i].cap>0) and (d[v]=d[j]+1) then beginret:=sap(j,min(flow-rec,edge[i].cap));dec(edge[i].cap,ret);inc(edge[i xor 1].cap,ret);cur[v]:=i;inc(rec,ret);if rec=flow then exit(flow);end;i:=edge[i].next;end;dec(num[d[v]]);if num[d[v]]=0 then d[ss]:=sum;inc(d[v]);inc(num[d[v]]);cur[v]:=first[v]; exit(rec);end;function maxflow:longint;varflow:longint;beginfillchar(num,sizeof(num),0);fillchar(d,sizeof(d),0);for i:=0 to sum do cur[i]:=first[i];num[0]:=sum;flow:=0;while d[ss]<sum do inc(flow,sap(ss,maxlongint)); exit(flow);end;procedure more(time:longint);vari,j,k:longint;begininc(sum,n+2);inc(num[0],n+2);if time=0 then addedge(ss,cal(s,time),kk);addedge(cal(t,time),st,maxlongint);if time>0 then beginfor i:=s to n do addedge(cal(i,time-1),cal(i,time),maxlongint);addedge(cal(t,time-1),cal(t,time),maxlongint);for i:=1 to m do beginj:=time mod c[i,0]+1;k:=time mod c[i,0];if k=0 then k:=c[i,0];addedge(cal(c[i,k],time-1),cal(c[i,j],time),h[i]);end; end;end;beginreadln(n,m,kk);leftk:=kk;fillchar(edge,sizeof(edge),0);fillchar(num,sizeof(num),0);for i:=0 to 200*(n+2) do first[i]:=-1;tot:=0;s:=0;t:=n+1;ss:=0;st:=1;sum:=2;num[0]:=2;for i:=1 to m do beginread(h[i],c[i,0]);for j:=1 to c[i][0] do beginread(c[i,j]);if c[i,j]=-1 then c[i,j]:=n+1;end;readln;end;time:=0;while time<200 do beginmore(time);flow:=0;inc(flow,maxflow);dec(leftk,flow);if leftk<=0 then beginwriteln(time);break;end;inc(time);end; if time=200 then writeln('0');end. View Codevijos 1653 瘋狂方格取數(shù)
? ?zkw處理負(fù)邊上跪了很久。網(wǎng)上少有資料
const maxn= 100000;typeedgetype=recordtoward,cap,cost,next:longint;end;varedge:array[0..maxn] of edgetype;map:array[1..1000,1..1000,0..1] of longint;q,first,slack,d,dist:array[0..maxn] of longint;pd:array[0..maxn] of boolean;i,j,n,m,ss,st,tot,k,x,cnt,point,mincost:longint;function min(x,y:longint):longint;beginif x<y then exit(x) else exit(y);end;procedure add(i,j,k,l:longint);beginedge[tot].toward:=j;edge[tot].cap:=k;edge[tot].cost:=l;edge[tot].next:=first[i];first[i]:=tot;inc(tot);end;procedure addedge(i,j,k,l:longint);beginadd(i,j,k,l);add(j,i,0,-l);end;procedure spfa;var head,tail,i,j,tmp,value:longint;beginfillchar(pd,sizeof(pd),false);for i:= ss to st do d[i]:=maxlongint;head:=1;tail:=1;q[1]:=ss;pd[ss]:=true;d[ss]:=0;while head<=tail dobeginj:=q[head];i:=first[j];while i<>-1 dobegintmp:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (d[tmp]>d[j]+value) thenbegind[tmp]:=d[j]+value;if not pd[tmp] thenbegininc(tail);if tail=maxn then tail:=1;q[tail]:=tmp;pd[tmp]:=true;end;end;i:=edge[i].next;end;inc(head);if head=maxn then head:=1;pd[j]:=false;end;end;procedure dfs(v:longint);var i,value,tmp:longint;beginpd[v]:=true;i:=first[v];while i<>-1 dobegintmp:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (not pd[tmp]) and (d[tmp]=d[v]+value) thenbegindist[tmp]:=dist[v]-value;dfs(tmp);end;i:=edge[i].next;end;end;function aug(v,flow:longint):longint;var rec,ret,i,tmp,value:longint;beginif v=st thenbegininc(mincost,flow*(dist[st]-dist[ss]));exit(flow);end;rec:=0;i:=first[v];pd[v]:=true;while i<>-1 dobegintmp:=edge[i].toward;value:=edge[i].cost;if (not pd[tmp]) and (edge[i].cap>0) thenif dist[v]=dist[tmp]+value thenbeginret:=aug(tmp,min(flow-rec,edge[i].cap));dec(edge[i].cap,ret);inc(edge[i xor 1].cap,ret);inc(rec,ret);if rec=flow then exit(flow);endelse slack[tmp]:=min(slack[tmp],dist[tmp]+value-dist[v]);i:=edge[i].next;end;exit(rec);end;function relabel:boolean;var i,delta:longint;begindelta:=maxlongint;for i:= ss to st do if not pd[i] then delta:=min(delta,slack[i]);if delta=maxlongint then exit(false);for i:= ss to st do if pd[i] then inc(dist[i],delta);exit(true);end;procedure init;beginreadln(k,m,n);cnt:=m*n;ss:=0;st:=cnt*2+1;tot:=0;point:=0;for i:= ss to st do first[i]:=-1;for i:=1 to n dofor j:= 1 to m dobeginread(x);inc(point);map[i,j,0]:=point;inc(point);map[i,j,1]:=point;addedge(map[i,j,0],map[i,j,1],1,-x);addedge(map[i,j,0],map[i,j,1],maxlongint,0);end;addedge(ss,map[1,1,0],k,0);addedge(map[n,m,1],st,k,0);for i:=1 to n dofor j:= 1 to m dobeginif i+1<=n then addedge(map[i,j,1],map[i+1,j,0],maxlongint,0);if j+1<=m then addedge(map[i,j,1],map[i,j+1,0],maxlongint,0);end;end;procedure costflow;beginspfa;fillchar(pd,sizeof(pd),false);fillchar(dist,sizeof(dist),0);dfs(ss);repeatfor i:= ss to st do slack[i]:=maxlongint;repeatfillchar(pd,sizeof(pd),false);until aug(ss,maxlongint)<=0;until not relabel;end;Begininit;costflow;writeln(mincost);end. View Codevijos 1726 美食節(jié)(費(fèi)用流)
? ? 很明顯是一道費(fèi)用流,如果用常規(guī)的方法,把每個(gè)廚師每個(gè)時(shí)刻拆出來(lái)的話,由于點(diǎn)太多會(huì)爆于是我們考慮了這樣一個(gè)事實(shí),每個(gè)廚師并不需要把他每個(gè)時(shí)刻的點(diǎn)都擴(kuò)展出來(lái),一個(gè)廚師只有當(dāng)他做完一個(gè)菜是才去考慮讓他多做一個(gè)菜,這樣的話由于一種只有sum(=∑p[i])道菜,所有整個(gè)圖實(shí)際需要的點(diǎn)數(shù)就是源點(diǎn)匯點(diǎn)(2個(gè)),菜(n個(gè)),廚師(m個(gè))以及擴(kuò)展出來(lái)的廚師(sum個(gè),實(shí)際只需sum-m,但為了方法我們不妨多幾個(gè)點(diǎn))。一開(kāi)始源點(diǎn)連每道菜連一條容量為菜需求量費(fèi)用為0的邊,匯點(diǎn)和每個(gè)廚師連一條容量為1費(fèi)用為0的邊,然后把第i個(gè)廚師與第j道菜連一條容量為1費(fèi)用為廚師做這道菜的時(shí)間的邊。這樣就是一個(gè)初始圖。跑spfa(由于一次一定是做一道菜,所以就可以省點(diǎn)記錄此次增廣的流量),然后每次增廣后必然會(huì)有一個(gè)廚師做出了某道菜,這是我們就掃一遍判斷是哪個(gè)廚師做了菜(開(kāi)個(gè)last數(shù)組記錄每個(gè)廚師當(dāng)前點(diǎn)與匯點(diǎn)的邊,判斷哪個(gè)廚師的最后一條邊容量為0),然后開(kāi)個(gè)chef表示這個(gè)廚師至今做了多少道菜。重新增加一個(gè)點(diǎn),這個(gè)點(diǎn)與每道菜連一條容量為1費(fèi)用為(這個(gè)廚師做這道菜的時(shí)間*這個(gè)廚師一共做了多少道菜),然后這個(gè)點(diǎn)再與匯點(diǎn)連一條容量為1費(fèi)用為0的邊。開(kāi)個(gè)time計(jì)菜,等time=sum時(shí)就說(shuō)明做完了,輸出這時(shí)的費(fèi)用就是答案了。
const maxn=300000;typeedgetype=recordtoward,cap,cost,next:longint;end;varedge:array[0..maxn] of edgetype;minflow,pre,first,q,dist:array[0..maxn] of longint;pd:array[0..maxn] of boolean;p:array[1..40] of longint;data:array[1..40,1..100] of longint;chef:array[1..100] of longint;last:array[1..100] of longint;i,j,s,t,n,m,tot,cnt,time,x:longint;function min(x,y:longint):longint;beginif x<y then exit(x) else exit(y);end;procedure add(i,j,k,l:longint);beginedge[tot].toward:=j;edge[tot].cap:=k;edge[tot].cost:=l;edge[tot].next:=first[i];first[i]:=tot;inc(tot);end;procedure addedge(i,j,k,l:longint);beginadd(i,j,k,l);add(j,i,0,-l);end;function spfa:boolean;var tmp,value,i,j,head,tail:longint;beginfillchar(pd,sizeof(pd),false);for i:=0 to t do dist[i]:=maxlongint;head:=1;tail:=1;q[tail]:=s;pd[s]:=true;dist[s]:=0;while head<=tail dobeginj:=q[head];i:=first[j];while i<>-1 dobegintmp:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (dist[tmp]>dist[j]+value) thenbegindist[tmp]:=dist[j]+value;pre[tmp]:=i;if not pd[tmp] thenbegininc(tail);q[tail]:=tmp;pd[tmp]:=true;end;end;i:=edge[i].next;end;inc(head);pd[j]:=false;end;if dist[t]=maxlongint then exit(false) else exit(true);end;function mcmf:longint;var u,cost:longint;begincost:=0;while time<cnt dobeginif not spfa then break;u:=t;while u<>s dobegindec(edge[pre[u]].cap);inc(edge[pre[u] xor 1].cap);u:=edge[pre[u] xor 1].toward;end;inc(cost,dist[t]);inc(time);for i:= 1 to m doif edge[last[i]].cap=0 thenbeginx:=i;break;end;inc(chef[x]);for i:=1 to n doaddedge(i,n+m+time,1,data[i,x]*chef[x]);addedge(n+m+time,t,1,0);last[x]:=tot-2;end;exit(cost);end;procedure init;begintot:=0;time:=0;cnt:=0;read(n,m);for i:=1 to n dobeginread(p[i]);inc(cnt,p[i]);end;for i:= 1 to n dofor j:= 1 to m doread(data[i,j]);s:=n+m+cnt+1; t:=s+1;for i:= 0 to t do first[i]:=-1;for i:=1 to n doaddedge(s,i,p[i],0);for i:=1 to n dofor j:= 1 to m doaddedge(i,j+n,1,data[i,j]);for i:= 1 to m do chef[i]:=1;for i:=1 to m dobeginaddedge(n+i,t,1,0);last[i]:=tot-2;end;end;Begininit;writeln(mcmf);End. View Codevijos 1621 終極情報(bào)網(wǎng)(費(fèi)用流)
? 網(wǎng)上沒(méi)有太多題解,因?yàn)檫@本來(lái)就是一道很簡(jiǎn)單的模型,這么簡(jiǎn)單就不想說(shuō)了,這道題主要難在兩個(gè)問(wèn)題,一個(gè)是要保留五位有效數(shù)字,一個(gè)是關(guān)于浮點(diǎn)運(yùn)算(后面這個(gè)東西害得我兩節(jié)晚自修沒(méi)了,網(wǎng)上也沒(méi)大神說(shuō)一下,第一次遇到浮點(diǎn)運(yùn)算什么的好討厭)。前一種我很傻很天真的方法yy然后就完了,但是很難看,下面會(huì)給出某蔡大神的空間自行過(guò)去研究他的吧。關(guān)于第二個(gè)問(wèn)題,這題是求一些實(shí)數(shù)的運(yùn)算,可以用兩個(gè)方法,一個(gè)是直接乘,就是把原來(lái)的spfa中+號(hào)改為*號(hào),那么相應(yīng)的,建邊的時(shí)候反向弧的費(fèi)用就不是-asi而是1/asi,這樣就會(huì)遇到一個(gè)精度問(wèn)題,所有在增廣時(shí)必須要把原來(lái)的dist[to]<dist[i]*edge[j].cost改為dist[i]*edge[j].cost-dist[to]>esp(esp=0.000000001)。這樣程序才跑得動(dòng)……第二種方法就是取對(duì)數(shù),把*改為+,覺(jué)得神奇到不可思議,所以還是由蔡大神的題解來(lái)告訴我們這些蒟蒻吧。
typearr=recordtoward,next,cap:longint;cost:double;end;varedge:array[0..1000000]of arr;dist,minc,a:array[0..100000]of double;q,first,pre,minf,b:array[0..100000]of longint;map:array[0..2000,0..2000]of double;i,j,k,l,s,t,tot,kk,maxflow,n,x:longint;chose:array[0..10000]of boolean;spent,h:double;function exp(x:double;y:longint):double; //快速冪遞歸版!yy一下就知道為什么用快速冪了beginif y=1 then exit(x);exit(exp(x,y div 2)*exp(x,y-(y div 2)));end;function min(x,y:longint):longint;beginif x>y then exit(y);exit(x);end;procedure add(i,j,k:longint;l:double);beginedge[tot].toward:=j;edge[tot].cap:=k;edge[tot].cost:=l;edge[tot].next:=first[i];first[i]:=tot;inc(tot);end;procedure addedge(i,j,k:longint;l:double);beginadd(i,j,k,l);add(j,i,0,1/l);end;function spfa:boolean;vari,head,tail,flow,j,too:longint;value,mm:double;beginfillchar(chose,sizeof(chose),false);fillchar(dist,sizeof(dist),0);dist[s]:=1;head:=1;tail:=1;q[1]:=s;mm:=0.000000001;chose[s]:=true;minf[s]:=maxlongint;while head<=tail do begini:=q[head];j:=first[i];while j<>-1 do begintoo:=edge[j].toward;value:=edge[j].cost;if (edge[j].cap>0) and (dist[i]*value-dist[too]>mm) then begindist[too]:=dist[i]*value;pre[too]:=j;minf[too]:=min(minf[i],edge[j].cap);minc[too]:=edge[j].cost;if not chose[too] then beginchose[too]:=true;inc(tail);q[tail]:=too;end;end;j:=edge[j].next;end;inc(head);chose[i]:=false;end;if dist[t]=0 then exit(false);exit(true);end;procedure mcmf;varj,k,v:longint;beginspent:=1;maxflow:=0;while spfa do beginj:=minf[t];inc(maxflow,j);v:=t;while v<>s do beginspent:=spent*exp(minc[v],j);k:=pre[v];dec(edge[k].cap,j);inc(edge[k xor 1].cap,j);v:=edge[k xor 1].toward;end;end;end;procedure outo;varans,i,j,k:longint;begin{writeln(spent);}spent:=spent*10;i:=1;x:=trunc(spent);while x=0 do beginspent:=spent*10;inc(i);x:=trunc(spent);end;spent:=spent/10;j:=0;while j<=5 do begininc(j);spent:=spent*10;b[j]:=trunc(spent);spent:=spent-b[j];end;if b[6]>=5 then inc(b[5]);k:=5;while (b[k]>=10) and (k>1) do begininc(b[k-1]);b[k]:=b[k]-10;end;if b[1]>9 thendec(i);write('0.');for k:=1 to i-1dowrite(0);for k:=1 to 5 dowrite(b[k]);readln;readln;readln;end;beginreadln(n,kk);fillchar(map,sizeof(map),0);t:=n+2;s:=n+1;tot:=0;for i:=0 to n+3 do first[i]:=-1;for i:=1 to n do read(a[i]);for i:=1 to n do beginread(b[i]);if b[i]>0 thenaddedge(s,i,b[i],a[i]);end;readln;for i:=1 to n do beginread(x);if x>0 then addedge(i,t,maxlongint,1);end;readln;read(j,k);while (j<>-1) and (k<>-1) do beginreadln(h,l);addedge(j,k,l,h);addedge(k,j,l,h);read(j,k);end;addedge(t,t+1,kk,1);inc(t);mcmf;if maxflow<kk then writeln('0')else outo;end. View Codevijos 1525 生命之泉 (費(fèi)用流)
? ?這道題和志愿者招募那道題差不多,屬于一個(gè)類型的,志愿者招募那道題網(wǎng)上可以找個(gè)很多好的題解!關(guān)于這類題簡(jiǎn)單的說(shuō)就是寫一些方程,然后會(huì)發(fā)現(xiàn)一些規(guī)律
最核心的就是:
一開(kāi)始)P[1]=X[1]≥2
?
? ? ? ? P[2]=X[1]+X[2]≥3
?
? ? ? ? P[3]=X[2]+X[3]≥2
可變?yōu)?#xff09;
? ? ? ?P[1]=X[1]-Y[1]=2
?
? ? ? ?P[2]=X[1]+X[2]-Y[2]=3
?
? ? ? ?P[3]=X[2]+X[3]-Y[3]=2 ? ?(Y就是一個(gè)變量就對(duì)了)
然后我們?cè)谧钋懊婕右粋€(gè) P[0]=0的式子,用下一個(gè)式子減上一個(gè)式子就可以得到
? ? ? ?P[1]-P[0]=X[1]-Y[1]=2
? ? ? ?P[2]-P[1]=X[2]+Y[1]-Y[2]=1
? ? ? ?P[3]-P[2]=-X[1]+X[3]+Y[2]-Y[3]=-1
? ? ? ?P[4]-P[3]=-X[2]-X[3]+Y[3]=-2
將常數(shù)項(xiàng)左移,得
? ? ? ?P[1]-P[0]=X[1]-Y[1]-2=0
? ? ? ?P[2]-P[1]=X[2]+Y[1]-Y[2]-1=0
? ? ? ?P[3]-P[2]=-X[1]+X[3]+Y[2]-Y[3]+1=0
? ? ? ?P[4]-P[3]=-X[2]-X[3]+Y[3]+2=0
我們發(fā)現(xiàn)一個(gè)x或y只會(huì)在兩個(gè)式子里面出現(xiàn),而且一個(gè)是負(fù)的,一個(gè)是正的!(大神話:很容易聯(lián)想到網(wǎng)絡(luò)流)
對(duì)于每個(gè)x[i],從-x[i]想+x[i]連一條邊(具體要根據(jù)題意),對(duì)于每個(gè)y[i]也是一樣,不過(guò)y[i]和-y[i]總是出現(xiàn)在一前一后。
這道題比較麻煩……要把最大費(fèi)用最大流然后轉(zhuǎn)為最小費(fèi)用最大流跑zkw……
typearr=recordtoward,cap,cost,next:longint;end;const maxn=1000000;varedge:array[0..10000]of arr;first,d,dist,q,slack:array[0..100000]of longint;chose:array[0..100000]of boolean;i,j,k,l,s,t,n,m,tot,maxcost,maxflow,kk:longint;procedure add(i,j,k,l:longint);beginedge[tot].toward:=j;edge[tot].cap:=k;edge[tot].cost:=l;edge[tot].next:=first[i];first[i]:=tot;inc(tot);end;procedure addedge(i,j,k,l:longint);beginadd(i,j,k,l);add(j,i,0,-l);end;function min(x,y:longint):longint;beginif x>y then exit(y);exit(x);end;procedure spfa;varhead,tail,i,too,value:longint;beginfillchar(chose,sizeof(chose),false);for i:=0 to t do d[i]:=maxlongint;head:=1;tail:=1;q[1]:=s;chose[s]:=true;d[s]:=0;while head<=tail do beginj:=q[head];i:=first[j];while i<>-1 do begintoo:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (d[too]>d[j]+value) then begind[too]:=d[j]+value;if not chose[too] then begininc(tail);if tail=maxn then tail:=1;q[tail]:=too;chose[too]:=true;end;end;i:=edge[i].next;end;inc(head);if head=maxn then head:=1;chose[j]:=false;end;end;procedure dfs(v:longint);vari,value,too:longint;beginchose[v]:=true;i:=first[v];while i<>-1 do begintoo:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (not chose[too]) and (d[too]=d[v]+value) then begindist[too]:=dist[v]-value;dfs(too);end;i:=edge[i].next;end;end;function aug(v,flow:longint):longint;varrec,ret,too,value,i:longint;beginif v=t then begininc(maxcost,(dist[t]-dist[s])*flow);inc(maxflow,flow);exit(flow);end;i:=first[v];chose[v]:=true;rec:=0;while i<>-1 do begintoo:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (not chose[too]) thenif dist[v]=dist[too]+value then beginret:=aug(too,min(flow-rec,edge[i].cap));dec(edge[i].cap,ret);inc(edge[i xor 1].cap,ret);inc(rec,ret);if rec=flow then exit(flow);end elseslack[too]:=min(slack[too],dist[too]+value-dist[v]);i:=edge[i].next;end;exit(rec);end;function rel:boolean;varspent,i:longint;beginspent:=maxlongint;for i:=0 to t doif not chose[i] then spent:=min(spent,slack[i]);if spent=maxlongint then exit(false);for i:=0 to t doif chose[i] then inc(dist[i],spent);exit(true);end;procedure costflow;beginspfa;fillchar(chose,sizeof(chose),false);fillchar(dist,sizeof(dist),0);dfs(s);repeatfor i:=0 to t do slack[i]:=maxlongint;repeatfillchar(chose,sizeof(chose),false);until aug(s,maxlongint)<=0;until not rel;end;procedure into;beginreadln(n,m,kk);s:=0;t:=n+2;tot:=0;for i:=0 to t do first[i]:=-1;addedge(1,t,kk,0);addedge(s,n+1,kk,0);for i:=1 to m do beginreadln(j,k,l);addedge(k+1,j,1,-l);end;for i:=1 to n doaddedge(i+1,i,maxlongint,0);fillchar(d,sizeof(d),0);end;begininto;costflow;writeln(maxcost);readln;readln;end. View Codevijos 1499 炸毀燃料庫(kù)
? ?建邊一直跪……為了容易想容易看,結(jié)果竟然就跪了……
? ?后來(lái)認(rèn)真想了好久(Orz蔡大神的代碼)才終于過(guò)了……線性規(guī)劃
一開(kāi)始
? ?x[1]+x[2]+x[3]+...+x[m] ? <=k;
? ?x[2]+x[3]+x[4]+...+x[m+1] <=k;
? ?x[3]+x[4]+x[5]+...+x[m+2] <=k;
? ?......
? ?x[n-m+1]+...+x[n] ? ? ? ? <=k;
轉(zhuǎn)換為
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0=0
? ?x[1]+x[2]+x[3]+...+x[m] ? -y[1]-k=0;
? ?x[2]+x[3]+x[4]+...+x[m+1] -y[2]-k=0;
? ?x[3]+x[4]+x[5]+...+x[m+2] -y[3]-k=0;
? ?...
? ?x[n-m+1]+...+x[n] -y[n-m+1]-k=0;
下面減上面
??
1 ? x[1]+x[2]+x[3]+...+x[m] ?-y[1]-k=0
2 ? x[m+1] ?-x[1] ? ? ? ? ?+y[1]-y[2] =0;
3 ? x[m+2] ?-x[2] ? ? ? ? ?+y[2]-y[3] =0;
4 ? x[m+3] ?-x[3] ? ? ? ? ?+y[3]-y[4] =0;
? ?......
( ? ?x[m+m] ?-x[m] ? ? ? ? ?+y[m]-y[m+1]=0
? ? x[m+m+1]-x[m+1] ? ? ? ? ? ? )
? ?......
n-m+1 ? x[n] ? ?-x[n-m] ? ? ? ?+y[n-m]-y[n-m+1]=0;
n-m+2 ?-x[n-m+1]-x[n-m]...-x[n]+y[n-m+1]+k=0
然后就是中間那種情況會(huì)導(dǎo)致圖有兩種結(jié)果,判斷條件是m≥n-m 是的話就是第一種圖(沒(méi)有括號(hào)那種情況),不是的話就是(有括號(hào)的圖)
?
typearr=recordtoward,next,cap,cost:longint;end;constmm=1000000;varedge:array[0..100000]of arr;first,dist,d,q,slack,a:array[0..mm]of longint;i,j,k,l,n,m,s,t,tot,maxcost,maxflow,kk:longint;chose:array[0..mm]of boolean;procedure add(i,j,k,l:longint);beginedge[tot].toward:=j;edge[tot].cap:=k;edge[tot].cost:=l;edge[tot].next:=first[i];first[i]:=tot;inc(tot);end;procedure addedge(i,j,k,l:longint);beginadd(i,j,k,l);add(j,i,0,-l);end;function min(x,y:longint):longint;beginif x>y then exit(y);exit(x);end;procedure spfa;varhead,tail,i,too,value:longint;beginfillchar(chose,sizeof(chose),false);for i:=0 to t do d[i]:=maxlongint;head:=1;tail:=1;q[1]:=s;chose[s]:=true;d[s]:=0;while head<=tail do beginj:=q[head];i:=first[j];while i<>-1 do begintoo:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (d[too]>d[j]+value) then begind[too]:=d[j]+value;if not chose[too] then begininc(tail);if tail=mm then tail:=1;q[tail]:=too;chose[too]:=true;end;end;i:=edge[i].next;end;inc(head);if head=mm then head:=1;chose[j]:=false;end;end;procedure dfs(v:longint);vari,value,too:longint;beginchose[v]:=true;i:=first[v];while i<>-1 do begintoo:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (d[too]=d[v]+value) then begindist[too]:=dist[v]-value;dfs(too);end;i:=edge[i].next;end;end;function aug(v,flow:longint):longint;varrec,ret,i,too,value:longint;beginif v=t then begininc(maxcost,(dist[t]-dist[s])*flow);inc(maxflow,flow);exit(flow);end;rec:=0;chose[v]:=true;i:=first[v];while i<>-1 do begintoo:=edge[i].toward;value:=edge[i].cost;if (edge[i].cap>0) and (not chose[too]) thenif dist[v]=dist[too]+value then beginret:=aug(too,min(flow-rec,edge[i].cap));dec(edge[i].cap,ret);inc(edge[i xor 1].cap,ret);inc(rec,ret);if rec=flow then exit(flow);end elseslack[too]:=min(slack[too],dist[too]+value-dist[v]);i:=edge[i].next;end;exit(rec);end;function rel:boolean;varspent,i:longint;beginspent:=maxlongint;for i:=0 to t doif not chose[i] then spent:=min(spent,slack[i]);if spent=maxlongint then exit(false);for i:=0 to t doif chose[i] then inc(dist[i],spent);exit(true);end;procedure maxc;beginspfa;fillchar(chose,sizeof(chose),false);fillchar(dist,sizeof(dist),0);dfs(s);repeatfor i:=0 to t do slack[i]:=maxlongint;repeatfillchar(chose,sizeof(chose),false);until aug(s,maxlongint)<=0;until not rel;end;procedure into;beginreadln(n,m,kk);s:=0;t:=n-m+3;for i:=0 to t do first[i]:=-1;tot:=0;for i:=1 to n doread(a[i]);addedge(s,n-m+2,kk,0);addedge(1,t,kk,0);if m>=n-m then beginfor i:=1 to n-m doaddedge(i+1,1,1,-a[i]);for i:=n-m+1 to m doaddedge(n-m+2,1,1,-a[i]);for i:=m+1 to n doaddedge(n-m+2,i-m+1,1,-a[i]);end else beginfor i:=1 to m doaddedge(i+1,1,1,-a[i]);for i:=m+1 to n-m doaddedge(i+1,i-m+1,1,-a[i]);for i:=n-m+1 to n doaddedge(n-m+2,i-m+1,1,-a[i]);end;for i:=1 to n-m+1 doaddedge(i+1,i,maxlongint,0);fillchar(d,sizeof(d),0);end;begininto;maxc;writeln(maxcost);end. View Codevijos 1734 海拔 (網(wǎng)絡(luò)流轉(zhuǎn)為最短路)
? ?orz這題特別神奇,作為蒟蒻完全被考倒了。
? ?找了網(wǎng)上的題解最好的就是這個(gè)了http://blog.sina.com.cn/s/blog_86942b1401014ajk.html?(其實(shí)有另一個(gè)……但是莫名掛了,orz)。
? ?這題很容易想到一個(gè)最小割模型,但是會(huì)tle!所以只能轉(zhuǎn)為對(duì)偶圖,這個(gè)神奇的東西推薦去看集訓(xùn)隊(duì)論文:周冬《兩極相通——淺析最大—最小定理在信息學(xué)競(jìng)賽中的應(yīng)用》。講的很詳細(xì)!
? ?然后就是spfa,裸的spfa不能過(guò),所以要加lll+slt優(yōu)化!
? ?或者是二叉堆優(yōu)化的dij……
? ?然后這題由于信息量太大就跪了很久……先搞懂一系列概念,然后就是略蛋疼的spfa了,在tle無(wú)數(shù)次后終于把spfa改的能過(guò)最后一個(gè)點(diǎn)(一直卡最后一個(gè)點(diǎn)orz)……
//spfa版 typearr=recordtoward,next,cost:longint;end;constmm=300000;varedge:array[0..5*mm]of arr;first,d,q:array[0..mm]of longint;map:array[0..2000,0..2000]of longint;f:array[0..mm]of boolean;i,j,k,l,n,m,tot,s,t,sum:longint;procedure addedge(i,j,k:longint);begininc(tot);edge[tot].toward:=j;edge[tot].next:=first[i];first[i]:=tot;edge[tot].cost:=k;end;procedure spfa(v:longint);varhead,tail,i,too,j,value,len,k:longint;sum:int64;beginsum:=0;len:=1;fillchar(f,sizeof(f),false);fillchar(d,sizeof(d),$7f);d[v]:=0;head:=0;tail:=1;q[1]:=v;f[v]:=true;while head<>tail do begininc(head);if head>mm then head:=1;while d[q[head]]>sum div len do begin //lll優(yōu)化,記得sum要int64!因?yàn)檫@個(gè)跪了一節(jié)晚自修!inc(tail);if tail>mm then tail:=1;q[tail]:=q[head];inc(head);if head>mm then head:=1;end;j:=q[head];i:=first[j];dec(len);dec(sum,d[j]);while i<>-1 do beginvalue:=edge[i].cost;too:=edge[i].toward;if (d[j]+value<d[too]) then begind[too]:=d[j]+value;if (not f[too]) and (d[too]<d[t])then begin //d[too]<d[t] 這步很神奇!inc(len);inc(sum,d[too]);k:=head+1;if k>mm then k:=1;if d[too]<d[q[k]] then begin //slf優(yōu)化f[too]:=true;q[head]:=too;head:=head-1;if head<1 then head:=mm;end else beginf[too]:=true;inc(tail);if tail>mm then tail:=1;q[tail]:=too;end;end;end;i:=edge[i].next;end;f[j]:=false;end;end;procedure into;begins:=0;t:=n*n+1;sum:=0;tot:=0;for i:=0 to n domap[0,i]:=t;for i:=0 to n domap[i,n+1]:=t;for i:=0 to n domap[i,0]:=s;for i:=0 to n domap[n+1,i]:=s;for i:=1 to n dofor j:=1 to n do begininc(sum);map[i,j]:=sum;end;for i:=1 to n+1 dofor j:=1 to n do beginread(k);addedge(map[i,j],map[i-1,j],k);end;for i:=1 to n dofor j:=1 to n+1 do beginread(k);addedge(map[i,j-1],map[i,j],k);end;for i:=1 to n+1 dofor j:=1 to n do beginread(k);addedge(map[i-1,j],map[i,j],k);end;for i:=1 to n dofor j:=1 to n+1 do beginread(k);addedge(map[i,j],map[i,j-1],k);end;end;procedure outo;beginreadln(n);for i:=0 to n*n+2 do first[i]:=-1;end;beginouto;into;spfa(s);writeln(d[t]);end.//據(jù)說(shuō)這題dij快,然后就寫了下,果然快了很多&……typearr=recordtoward,next,cost:longint;end;ar=recordvalue,toward:longint;end;constmm=300000;varedge:array[0..5*mm]of arr;first,g:array[0..mm]of longint;head:array[0..5*mm]of ar;map:array[0..2000,0..2000]of longint;f:array[0..mm]of boolean;i,j,k,l,n,m,tot,s,t,sum,len:longint;procedure addedge(i,j,k:longint);begininc(tot);edge[tot].toward:=j;edge[tot].next:=g[i];g[i]:=tot;edge[tot].cost:=k;end;procedure into;begin readln(n);for i:=0 to n*n+2 do g[i]:=-1;s:=n*n+1;t:=n*n+2;sum:=0;tot:=0;for i:=0 to n domap[0,i]:=t;for i:=0 to n domap[i,n+1]:=t;for i:=0 to n domap[i,0]:=s;for i:=0 to n domap[n+1,i]:=s;for i:=1 to n dofor j:=1 to n do begininc(sum);map[i,j]:=sum;end;for i:=1 to n+1 dofor j:=1 to n do beginread(k);addedge(map[i,j],map[i-1,j],k);end;for i:=1 to n dofor j:=1 to n+1 do beginread(k);addedge(map[i,j-1],map[i,j],k);end;for i:=1 to n+1 dofor j:=1 to n do beginread(k);addedge(map[i-1,j],map[i,j],k);end;for i:=1 to n dofor j:=1 to n+1 do beginread(k);addedge(map[i,j],map[i,j-1],k);end;end;procedure swap(a,b:longint);varj:ar;beginj:=head[a];head[a]:=head[b];head[b]:=j;first[head[a].toward]:=a;first[head[b].toward]:=b;end;procedure decre(i:longint);beginwhile (i<>1) and (head[i].value<head[i shr 1].value) do beginswap(i,i shr 1);i:=i shr 1;end;end;procedure headpify;vari:longint;begini:=2;while i<=len do beginif (i<len) and (head[i+1].value<head[i].value) then inc(i);if head[i].value<head[i shr 1].value then beginswap(i,i shr 1);i:=i*2;endelse break;end;end;procedure relax(i,j,k:longint);beginif k+head[first[i]].value<head[first[j]].value then beginhead[first[j]].value:=k+head[first[i]].value;decre(first[j]);end;end;procedure dij;vari,too,va:longint;beginfor i:=1 to t do beginhead[i].toward:=i;head[i].value:=maxlongint;first[i]:=i;end;head[s].value:=0;swap(1,s);len:=t;while len>0 do begini:=head[1].toward;if i=t then exit;swap(1,len);dec(len);headpify;j:=g[i];while j<>-1 do begintoo:=edge[j].toward;va:=edge[j].cost;if first[too]<=len then relax(i,too,va);j:=edge[j].next;end;end;end;begininto;dij;writeln(head[1].value);end. View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/Macaulish/p/6492057.html
總結(jié)
以上是生活随笔為你收集整理的【以前的空间】网络流合集的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 张量基本概念
- 下一篇: 联想yoga13装win7步骤介绍