题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676
题意:
给出N个点和M条边,要求一个割集,使得集合中 ans = 所有边点权值和/边的数量 最小。
思路:
0-1分数规划。
具体证明参考 胡伯涛 《最小割模型在信息学竞赛中的应用》
设g = min(Σwi/Σ1)
转化为 求g使得 (Σwi - g*Σ1) = 0。
所以二分求g的值。
每次建图的时候,以1为源点,N为汇点。
原来图中每条边的容量 = wi-g。
要注意点是如果容量<0,那么这条边必在割集中。
如果容量>=0,在图中连起来然后求最小割。
最后输出边集。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <cstdio> 5 #include <queue> 6 #include <cmath> 7 #include <algorithm> 8 #include <vector> 9 using namespace std; 10 #define maxn 105 11 const double inf = 10000007; 12 const double eps = 1e-8; 13 struct Edge 14 { 15 int from, to, xh; 16 double cap, flow; 17 Edge(int f, int t, double c, double fl, int x) 18 { 19 from = f; to = t; cap = c; flow = fl; xh = x; 20 } 21 }; 22 struct Edge2 23 { 24 int from, to; 25 double cost; 26 }init[405]; 27 vector <Edge> edges; 28 vector <int> G[maxn]; 29 int n, m, s, t; 30 int vis[maxn], cur[maxn], d[maxn]; 31 double min(double a, double b) 32 { 33 return a<b?a:b; 34 } 35 void AddEdge(int from, int to, double cap, int xh) 36 { 37 edges.push_back(Edge(from, to, cap, 0, xh)); 38 edges.push_back(Edge(to, from, 0, 0, -1)); 39 m = edges.size(); 40 G[from].push_back(m-2); 41 G[to].push_back(m-1); 42 } 43 bool bfs() 44 { 45 memset(vis, 0, sizeof(vis)); 46 d[s] = 0; 47 vis[s] = 1; 48 queue <int> q; 49 q.push(s); 50 while(!q.empty()) 51 { 52 int u = q.front(); q.pop(); 53 for(int i = 0; i < G[u].size(); i++) 54 { 55 Edge &e = edges[G[u][i]]; 56 if(!vis[e.to] && e.cap-e.flow > eps) 57 { 58 vis[e.to] = 1; 59 d[e.to] = d[u]+1; 60 q.push(e.to); 61 } 62 } 63 } 64 return vis[t]; 65 } 66 double dfs(int x, double a) 67 { 68 if(x == t || fabs(a) <eps) return a; 69 double flow = 0, f; 70 for(int &i = cur[x]; i < G[x].size(); i++) 71 { 72 Edge &e = edges[G[x][i]]; 73 if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > eps) 74 { 75 e.flow += f; 76 edges[G[x][i]^1].flow -= f; 77 flow += f; 78 a -= f; 79 if(fabs(a) < eps) break; 80 } 81 } 82 return flow; 83 } 84 double Maxflow() 85 { 86 double flow = 0; 87 while(bfs()) 88 { 89 memset(cur, 0, sizeof(cur)); 90 flow += dfs(s, inf); 91 } 92 return flow; 93 } 94 int N, M; 95 int main() 96 { 97 while(~scanf("%d%d", &N, &M)) 98 { 99 for(int i = 1; i <= M; i++) 100 { 101 scanf("%d%d%lf", &init[i].from, &init[i].to, &init[i].cost); 102 } 103 double l = 0, r = 10000001; 104 s = 1, t = N; n = N; 105 double mid; 106 double sum = 0; 107 while(l+eps <= r) 108 { 109 edges.clear(); 110 for(int i = 1; i <= N; i++) G[i].clear(); 111 mid = (l+r)/2.0; 112 sum = 0; 113 for(int i = 1; i <= M; i++) 114 { 115 double temp = init[i].cost - mid; 116 if(temp < 0) sum += temp; 117 else 118 { 119 AddEdge(init[i].from, init[i].to, temp, i); 120 AddEdge(init[i].to, init[i].from, temp, i); 121 } 122 } 123 sum += Maxflow(); 124 if(sum >= eps) l = mid; 125 else r = mid; 126 } 127 vector <int> ans; 128 edges.clear(); 129 for(int i = 1; i <= N; i++) G[i].clear(); 130 for(int i = 1; i <= M; i++) 131 { 132 double temp = init[i].cost - mid; 133 if(temp >= 0) 134 { 135 AddEdge(init[i].from, init[i].to, temp, i); 136 AddEdge(init[i].to, init[i].from, temp, i); 137 } 138 } 139 Maxflow(); 140 int cnt = 0; 141 for(int i = 1; i <= M; i++) 142 { 143 if((vis[init[i].from] + vis[init[i].to]) == 1 || init[i].cost + eps < mid) 144 { 145 cnt++; 146 } 147 } 148 printf("%d\n", cnt); 149 bool flag = true; 150 for(int i = 1; i <= M; i++) 151 { 152 if((vis[init[i].from] + vis[init[i].to]) == 1 || init[i].cost + eps < mid) 153 { 154 if(flag) 155 { 156 printf("%d", i); 157 flag = false; 158 } 159 else printf(" %d", i); 160 } 161 } 162 printf("\n"); 163 164 } 165 166 return 0; 167 }