舊題重WA 233ios
原題:網絡
n<=2000ide
一眼費用流,簡單spa
拆點,s到入點流量∞費用p表示直接買,入點到出點r[i]表示天天必須有r[i]條,出點到t流量∞用來保證邊被鴿掉,出點再到i+m或i+n的入點表示洗了,入點到下一天的入點流量∞表示洗過的能夠屯着code
而後樣例就過不了233blog
翻之前的博客,發現我三年前第一次作這題的時候就犯了一樣的錯誤233ci
我以前的博客認爲錯誤在於若是選擇洗,那麼這條餐巾的費用爲買+洗,大於直接買,因此不會增廣get
這個解釋不對,費用流就是在保證最大流的狀況下費用最小,那麼我先買再洗,每條邊跑的也是滿流,費用更低,爲何費用流得不到方案???博客
費用更低是確定的,費用流也沒問題,問題就在於每條邊跑滿流可不等於最大流string
這個錯誤主要仍是在最大流最小割的概念上不清楚
把中間的邊全鴿了,所用流量確實是最大流
可是上面的建圖若是先買再洗,那麼一條流鴿了兩條邊,總流量不是最大流
最大流最小割定理只能證實兩者在數值上相等
事實上,若是買+洗方案跑完的殘餘網絡(包括反邊)畫出來,就能夠發現有一條從源到入點,再從入點走反邊到出點的流量
這條反邊雖然讓費用增長,但也給從源到匯提供了再跑一次的機會
因此由此能夠總結經驗,注意最大流必定是從源點到匯點的流量呀
知道了錯誤的本質,正解其實不難理解
爲了不以前的錯誤,咱們要保證每條幹淨毛巾(無論是買的仍是洗的)都必須佔用一條從源到匯的完整流量
須要注意到一個關鍵性質,天天會穩定地產生r[i]條髒毛巾
那麼咱們產銷分離,把買的和洗的分開考慮
由於天天固定會產髒毛巾,因此也不須要再從乾淨的毛巾裏引一條邊出來表示洗
直接把天天拆稱髒點和好點,而後從髒點到i+m或i+n天的好點連邊,而後源再到髒點流量爲r[i],表示天天最多產r[i]條髒毛巾
源點再到好點連邊,表示直接買,好點到匯點流量爲r[i],表示天天必需要攢夠r[i]條好毛巾
最後,好點到下一天的好點連邊表示屯毛巾就好了
代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 #define LL long long 8 int rd(){int z=0,mk=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){if(ch=='-')mk=-1; ch=getchar();} 10 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 11 return z*mk; 12 } 13 const int oo=1000000007; 14 struct edg{int nxt,y,v,u;}e[31000]; int lk[4100],ltp=1; 15 void ist(int x,int y,int z,int w){ 16 e[++ltp]=(edg){lk[x],y,z,w}; lk[x]=ltp; 17 e[++ltp]=(edg){lk[y],x,0,-w}; lk[y]=ltp; 18 } 19 int n,m,ft,st,fc,sc,a[2100]; 20 int s,t; 21 int dstc[4100]; 22 int q[41000],hd=0; bool vstd[4100]; 23 int lst[4100],lse[4100]; 24 bool spfa(){ 25 for(int i=1;i<=t;++i){ 26 vstd[i]=false; 27 dstc[i]=oo; 28 } 29 dstc[q[hd=1]=s]=0; 30 for(int k=1;k<=hd;++k){ 31 for(int i=lk[q[k]];i;i=e[i].nxt) 32 if(e[i].v && dstc[q[k]]+e[i].u<dstc[e[i].y]){ 33 dstc[e[i].y]=dstc[q[k]]+e[i].u; 34 lst[e[i].y]=q[k],lse[e[i].y]=i; 35 if(!vstd[e[i].y]){ 36 q[++hd]=e[i].y; 37 vstd[e[i].y]=true; 38 } 39 } 40 vstd[q[k]]=false; 41 } 42 //return dstc[t]; 注意不是判斷dstc[t]不爲0 43 return dstc[t]!=oo; 44 } 45 LL cstflw(){ 46 LL bwl=0; 47 while(spfa()){ 48 int flw=oo; 49 for(int i=t;i!=s;i=lst[i]) 50 flw=min(flw,e[lse[i]].v); 51 for(int i=t;i!=s;i=lst[i]){ 52 bwl+=flw*e[lse[i]].u; 53 e[lse[i]].v-=flw,e[lse[i]^1].v+=flw; 54 //cout<<i<<"<-"; 55 } 56 //cout<<endl; 57 } 58 return bwl; 59 } 60 int main(){ 61 //freopen("ddd.in","r",stdin); 62 cin>>n; 63 for(int i=1;i<=n;++i) a[i]=rd(); 64 cin>>m>>ft>>fc>>st>>sc; 65 s=n+n+1,t=n+n+2; 66 for(int i=1;i<=n;++i){ 67 /*ist(i,i+n,a[i],0); 68 ist(s,i,oo,m); 69 ist(i+n,t,oo,0); 70 if(i<n) ist(i,i+1,oo,0); 71 if(i+ft<=n) ist(i+n,i+ft,oo,fc); 72 if(i+st<=n) ist(i+n,i+st,oo,sc);*/ 73 ist(s,i+n,oo,m); 74 ist(i+n,t,a[i],0); 75 ist(s,i,a[i],0); 76 if(i<n) ist(i,i+1,oo,0); 77 if(i+ft<=n) ist(i,i+ft+n,oo,fc); 78 if(i+st<=n) ist(i,i+st+n,oo,sc); 79 } 80 cout<<cstflw()<<endl; 81 return 0; 82 }