USACO 4.4 Pollutant Control(最小割,求最优解)
2015-03-25 16:52:22
思路:题意说了半天其实就是求最小割,然后输出。并且要求(1)流量相等时边数较小,(2)流量边数相等时要求边的编号字典序最小。
关于最小割,浏览了相关资料和07胡伯涛论文... 大概知道:
(1)最大流流量= 最小割流量。
(2)最小割把点分成S,T,其中起点 s ∈ S,终点 t ∈ T,割边就是e = {(u,v) | u ∈ S , v ∈ T}。
(3)最小割的边都满流,但满流的边并不一定属于最小割。
对于这题:
首先,要处理要求(1),看了别人的博客... 看到个很神的方法,把每条边的流量 × (M+1)+1,再跑最大流,得到Max_flow。
那么最大流流量为 Max_flow / (M+1),最小割的边数为 Max_flow % (M+1)。(思考!)
原因:不作处理的最大流仅能求出最小割的流量,但不能使边数较小。所以我们尝试给每条边附加一个权值又不至于影响最小割结果。
其次,要处理要求(2)及其输出解,可以从起点做一次 floodfill(其实就是从起点出发的DFS,沿着未满流的边的走),标记 S 点集。
再从终点做一次 floodfill(这是一种反向遍历),标记 T 点集合。那么 e = {(u,v) | (u∈S&&v∈T) || (u∉S&&v∉T)}。
也就是说某边为割边当且仅当该边的两个点不同时在S中或T中。
要保证边的编号的字典序最小只要按照输入的顺序检索所有边即可,直到符合要求边的数量 == 最小割边数。
1 /* 2 ID:naturec1 3 PROG: milk6 4 LANG: C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <cstdlib> 9 #include <cmath> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <string> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 20 #define MEM(a,b) memset(a,b,sizeof(a)) 21 #define REP(i,n) for(int i=1;i<=(n);++i) 22 #define REV(i,n) for(int i=(n);i>=1;--i) 23 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 24 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 25 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 26 #define MP(a,b) make_pair(a,b) 27 28 typedef long long ll; 29 typedef pair<int,int> pii; 30 const int INF = (1 << 30) - 1; 31 const int MAXN = 50; 32 const int MAXM = 1010; 33 34 int N,M,S[MAXN]; 35 struct edge{ 36 int u,v,next,id; 37 ll cp; 38 }; 39 40 struct Max_flow{ 41 int first[MAXN],ecnt; 42 int st,ed,lev[MAXN]; 43 edge e[MAXM * 8]; 44 void init(int tst,int ted){ 45 MEM(first,-1); 46 ecnt = 0; 47 st = tst; 48 ed = ted; 49 } 50 void add_edge(int u,int v,ll c,int id){ 51 e[ecnt].next = first[u]; 52 e[ecnt].u = u; 53 e[ecnt].v = v; 54 e[ecnt].id = id; 55 e[ecnt].cp = c; 56 first[u] = ecnt++; 57 58 e[ecnt].next = first[v]; 59 e[ecnt].u = v; 60 e[ecnt].v = u; 61 e[ecnt].id = id; 62 e[ecnt].cp = 0; 63 first[v] = ecnt++; 64 } 65 bool bfs(){ 66 queue<int> Q; 67 Q.push(st); 68 MEM(lev,-1); 69 lev[st] = 0; 70 while(!Q.empty()){ 71 int cur = Q.front(); Q.pop(); 72 for(int i = first[cur]; ~i; i = e[i].next){ 73 int v = e[i].v; 74 if(lev[v] < 0 && e[i].cp > 0){ 75 lev[v] = lev[cur] + 1; 76 Q.push(v); 77 } 78 } 79 } 80 return lev[ed] != -1; 81 } 82 ll dfs(int p,ll minf){ 83 if(p == ed) return minf; 84 for(int i = first[p]; ~i; i = e[i].next){ 85 int v = e[i].v; 86 if(lev[v] > lev[p] && e[i].cp > 0){ 87 ll d = dfs(v,min(e[i].cp,minf)); 88 if(d > 0){ 89 e[i].cp -= d; 90 e[i ^ 1].cp += d; 91 return d; 92 } 93 } 94 } 95 return 0; 96 } 97 ll dinic(){ 98 ll max_flow = 0,cur; 99 while(bfs()){ 100 while((cur = dfs(st,1LL << 60)) > 0) 101 max_flow += cur; 102 } 103 return max_flow; 104 } 105 void Flood_fill(int p){ 106 S[p] = 1; 107 for(int i = first[p]; ~i; i = e[i].next){ 108 int v = e[i].v; 109 if(S[v] || e[i].cp <= 0) continue; 110 Flood_fill(v); 111 } 112 } 113 void A_Flood_fill(int p){ 114 S[p] = -1; 115 for(int i = first[p]; ~i; i = e[i].next){ 116 int v = e[i].v; 117 if(S[v] || e[i ^ 1].cp <= 0) continue; 118 A_Flood_fill(v); 119 } 120 } 121 }MF; 122 123 int main(){ 124 freopen("milk6.in","r",stdin); 125 freopen("milk6.out","w",stdout); 126 int a,b; 127 ll c; 128 scanf("%d%d",&N,&M); 129 MF.init(1,N); 130 REP(i,M){ 131 scanf("%d%d%lld",&a,&b,&c); 132 c = c * (M + 1) + 1; 133 MF.add_edge(a,b,c,i); 134 //MF.add_edge(b,a,c,i); 135 } 136 ll tmax_flow = MF.dinic(); 137 MF.Flood_fill(MF.st); 138 MF.A_Flood_fill(MF.ed); 139 ll anscnt = tmax_flow % (M + 1); 140 printf("%lld %lld\n",tmax_flow / (M + 1),anscnt); 141 if(tmax_flow){ 142 int tcnt = 0; 143 for(int i = 0; tcnt < anscnt && i < MF.ecnt; i += 2){ 144 int tmp = S[MF.e[i].u] + S[MF.e[i].v]; 145 if(MF.e[i].cp == 0 && tmp != 2 && tmp != -2){ 146 printf("%d\n",MF.e[i].id); 147 ++tcnt; 148 } 149 } 150 } 151 return 0; 152 }