【網絡流24】餐巾

舊題重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 }
View Code
相關文章
相關標籤/搜索