1. 程式人生 > >USACO 4.4.2 追查壞牛奶 oj1341 網絡流最小割問題

USACO 4.4.2 追查壞牛奶 oj1341 網絡流最小割問題

+= source dinic fread ati script str one color

描述 Description
你第一天接手三鹿牛奶公司就發生了一件倒黴的事情:公司不小心發送了一批有三聚氰胺的牛奶。很不幸,你發現這件事的時候,有三聚氰胺的牛奶已經進入了送貨網。這個送貨網很大,而且關系復雜。你知道這批牛奶要發給哪個零售商,但是要把這批牛奶送到他手中有許多種途徑。送貨網由一些倉庫和運輸卡車組成,每輛卡車都在各自固定的兩個倉庫之間單向運輸牛奶。在追查這些有三聚氰胺的牛奶的時候,有必要保證它不被送到零售商手裏,所以必須使某些運輸卡車停止運輸,但是停止每輛卡車都會有一定的經濟損失。你的任務是,在保證壞牛奶不送到零售商的前提下,制定出停止卡車運輸的方案,使損失最小。
輸入格式 Input Format
第一行: 兩個整數N(2<=N<=32)、M(0<=M<=1000), N表示倉庫的數目,M表示運輸卡車的數量。倉庫1代 表發貨工廠,倉庫N代表有三聚氰胺的牛奶要發往的零售商。 第2..M+1行: 每行3個整數Si,Ei,Ci。其中Si,Ei表示這 輛卡車的出發倉庫,目的倉庫。Ci(0 <= C i <= 2,000,000) 表示讓這輛卡車停止運輸的損失。
輸出格式 Output Format
第1行兩個整數c、t,c表示最小的損失,T表示要停止的最少卡車數。接下來t 行表示你要停止哪幾條線路。如果有多種方案使損失最小,輸出停止的線路最少的方案。如果仍然還有相同的方案,請選擇開始輸入順序最小的。
樣例輸入 Sample Input

4 5
1 3 100
3 2 50
2 4 60
1 2 40
2 3 80

樣例輸出 Sample Output

60 1
3

時間限制 Time Limitation
1s
註釋 Hint
1s
來源 Source
usaco 4.4.2

不得不說這道題真的是毒,輸出最小割,割的邊數,以及割的方案。

因為只有1000條邊,我們將每條邊的流量*1001+1,求出最大流後/1001即是最大流【相信能理解】,%1001之後就是割的邊數【這也很好理解】。

  最難的第三個問題:輸出割的方案。雖然可以通過:枚舉每條邊,先去掉這條邊,然後再求最大流,如果最大流的減小值是這條邊的權值,那麽這條邊就在內,輸出即可。然而雖然數據量支持我們這麽做,但是OJ的數據..........1000條1到4的邊,流量都是2000000。雖然可以在評測姬變卡之後仍能過去【gy0.7s此點】,但是寫的不知道為什麽我自己本地0.9s。但是發現樹神有更高級的寫法:

  從源點進行DFS遍歷,如果到下一條邊流量不為0,繼續遍歷標記。最後對於每個點枚舉它的邊,如果x到y有邊,x標記,y為標記,說明這條邊在最小割中。然而OJ是有數據卡這個方法的。這個方法求的邊是第一個遇到的最小割,然而如果1 2 3 4四個點,之間流量都是10,邊如下:3 4 10,2 3 10,1 2 10。因為題目要求給出多種方法,按邊的序號字典序輸出,這四個點割一條邊,肯定是都可以的,正解是輸出1【3 4這條邊,序號為1】。但是圖中按此法顯然我們求出的是1 ,2。

  我們便可以發現問題了。但是這種數據只能用來卡序號,這就需要此方法求得的這條邊能導致後面不連通。那麽顯然這條邊流量是滿的。後面如果出現更優解【字典序更小】,那麽也必須流量是滿的,且流量一樣,並滿足邊數等於前面。

   但是,這也並不是正解,仍然會被卡掉。正解還是刪邊求最大流。

技術分享
  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define INF 2100000000
  4 using namespace std;
  5 int level[100];
  6 int q[100];
  7 int lin[100];
  8 int rev[5500];
  9 bool f[100]; 
 10 bool fe[5500];
 11 int len=0;
 12 ll ans=0;
 13 int cnt[5500];
 14 struct www
 15 {
 16     ll v;
 17     int id;    
 18 }a[40][40],b[40][40],c[1011];
 19 ll n,m;
 20 ll s,t;
 21 struct qaq{
 22     int nt,y;
 23     ll v;
 24 }e[5500];
 25 
 26 char buf[1<<15],*fs,*ft;
 27 inline char getc(){ return(fs==ft && (ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; }
 28 ll read()
 29 {
 30     ll x=0;
 31     char ch=getc();
 32     while(!isdigit(ch)) ch=getc();
 33     while(isdigit(ch)) {x=(x<<3)+(x<<1)+ch-0; ch=getc();}
 34     return x;
 35 }
 36 
 37 void insert(int x,int y,ll v)
 38 {
 39     e[++len].nt=lin[x]; e[len].v=v; e[len].y=y; lin[x]=len; rev[len]=len+1; fe[len]=1;
 40     e[++len].nt=lin[y]; e[len].v=0; e[len].y=x; lin[y]=len; rev[len]=len-1;
 41 }
 42 
 43 bool make_level()
 44 {
 45     ll head=0,tail=1;
 46     memset(level,-1,sizeof(level));
 47     q[1]=s;level[s]=0;
 48     while(head++<tail)
 49     {
 50         ll x=q[head];
 51         for(ll i=lin[x];i;i=e[i].nt)
 52             if(e[i].v && level[e[i].y]==-1)
 53             {
 54                 level[e[i].y]=level[x]+1;
 55                 q[++tail]=e[i].y;
 56             }
 57     }
 58     return level[t]>=0;
 59 }
 60 
 61 ll max_flow(ll k,ll flow)
 62 {
 63     if(k==t) return flow;
 64     ll maxflow=0;
 65     ll v;
 66     for(ll i=lin[k];i && (maxflow<flow);i=e[i].nt)
 67         if(e[i].v && level[e[i].y]==level[k]+1)
 68             if(v=max_flow(e[i].y,min(e[i].v,flow-maxflow)))
 69                 maxflow+=v,e[i].v-=v,e[rev[i]].v+=v;
 70     if(!maxflow) level[k]=-1;
 71     return maxflow;
 72 }
 73 
 74 ll dinic()
 75 {
 76     ans=0;
 77     ll v;
 78     while(make_level())
 79         while(v=max_flow(s,INF))
 80             ans+=v;
 81     return ans;
 82 }
 83 
 84 void dfs(int k)
 85 {
 86     f[k]=1;
 87     for(int i=lin[k];i;i=e[i].nt)
 88     {
 89         if(!f[e[i].y]&&e[i].v)
 90             dfs(e[i].y);
 91     }
 92 }
 93 
 94 int main()
 95 {
 96     freopen("a.txt","r",stdin);
 97     freopen("b.txt","w",stdout);
 98     n=read();
 99     m=read();
100     s=1,t=n;
101     for(ll i=1;i<=m;++i)
102     {
103         int x=read(),y=read();
104         ll v=read();
105         c[i].v=v;
106         insert(x,y,v*1001+1);
107     }
108     ll tmp=dinic();
109     //cout<<tmp<<endl;
110     printf("%lld %lld\n",tmp/1001,tmp%1001);
111     bool flag=0;
112     for(int i=1;i<=m;i++)
113         if(c[i].v==tmp/1001)
114         {
115             cout<<i<<endl;
116             flag=1;
117         }
118     if(flag==1) return 0;
119     dfs(1);
120     //cout<<"--------"<<endl;
121     //for(int i=1;i<=n;i++) cout<<f[i]<<‘ ‘;cout<<endl;
122     int haha=0;
123     for(int i=1;i<=n;i++)
124     {
125         for(int j=lin[i];j;j=e[j].nt)
126         {
127             if(f[i]&&!f[e[j].y]&&fe[j])
128                 cnt[++haha]=(j+1)>>1;
129         }
130     }
131     sort(cnt+1,cnt+1+haha);
132     for(int i=1;i<=haha;i++) cout<<cnt[i]<<endl;
133     return 0;
134 }
View Code

USACO 4.4.2 追查壞牛奶 oj1341 網絡流最小割問題