题目链接:http://poj.org/problem?id=3308
题意:
有一个M*N的图,上面的一些点上有伞兵。
可以设置一些枪在每行或者每列上,通过射击,这行或这列的伞兵就会被消灭。每个枪的设置有一个花费,如果设置多个枪,那么花费是设置每个枪的乘积。
问消灭所有伞兵最少的花费是多少。
思路:
每个点的伞兵至少要用那一列或者那一行设置的枪去消灭,那么就可以应用点覆盖的模型。把伞兵看成是一条边,这条边至少要用一个点来覆盖。
而题目中最终花费是所有花费的乘积,那么可以用对数log(x)+log(y) = log(x*y)来转换。
所以就可以用最小点权覆盖模型来解决。
设置一个超级源点s和超级汇点t。
s向每行连一条边,容量是log(在这些行设置枪的花费)。
每列向t连一条边,容量是log(在这些列设置枪的花费)。
对于每个伞兵所在的位置(x, y),则x向y连一条边,容量是inf。
然后求最小割。答案就是exp(最大流)。
这题要注意一下精度问题,esp开1e-8,因为保留4位小数。用G++时,双精度是%f,用C++时双精度是%lf。
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <cmath> 6 #include <queue> 7 #include <vector> 8 using namespace std; 9 struct Edge 10 { 11 int from, to; double cap, flow; 12 Edge(int f, int t, double c, double fl) 13 { 14 from = f; to = t; cap = c; flow = fl; 15 } 16 }; 17 #define maxn 110 18 #define inf 100000 19 #define eps 1e-8 20 int n, m, s, t; 21 vector <Edge> edges; 22 vector <int> G[maxn]; 23 int d[maxn], cur[maxn], vis[maxn]; 24 void AddEdge(int from, int to, double cap) 25 { 26 edges.push_back(Edge(from, to, cap, 0)); 27 edges.push_back(Edge(to, from, 0, 0)); 28 m = edges.size(); 29 G[from].push_back(m-2); 30 G[to].push_back(m-1); 31 } 32 bool bfs() 33 { 34 memset(vis, 0, sizeof(vis)); 35 d[s] = 0; vis[s] = 1; 36 queue <int> q; q.push(s); 37 while(!q.empty()) 38 { 39 int x = q.front(); q.pop(); 40 for(int i = 0; i < G[x].size(); i++) 41 { 42 Edge &e = edges[G[x][i]]; 43 if(!vis[e.to] && e.cap > e.flow) 44 { 45 d[e.to] = d[x] + 1; 46 vis[e.to] = 1; 47 q.push(e.to); 48 } 49 } 50 } 51 return vis[t]; 52 } 53 double dfs(int x, double a) 54 { 55 if(x == t || fabs(a) < eps) return a; 56 double flow = 0, f; 57 for(int &i = cur[x]; i < G[x].size(); i++) 58 { 59 Edge &e = edges[G[x][i]]; 60 if(d[e.to] == d[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) 61 { 62 e.flow += f; 63 edges[G[x][i]^1].flow -= f; 64 flow += f; 65 a -= f; 66 if(fabs(a) < eps) break; 67 } 68 } 69 return flow; 70 } 71 double maxflow() 72 { 73 double flow = 0; 74 while(bfs()) 75 { 76 memset(cur, 0, sizeof(cur)); 77 flow += dfs(s, inf); 78 } 79 return flow; 80 } 81 int T, M, N, L; 82 int main() 83 { 84 //freopen("in.txt", "r", stdin); 85 //freopen("out.txt", "w", stdout); 86 scanf("%d", &T); 87 while(T--) 88 { 89 scanf("%d%d%d", &M, &N, &L); 90 edges.clear(); 91 s = 0; t = N+M+1; n = N+M+2; 92 for(int i = s; i <= t; i++) G[i].clear(); 93 double val; 94 for(int i = 1; i <= M; i++) 95 { 96 scanf("%lf", &val); 97 AddEdge(s, i, log(val)); 98 } 99 for(int i = 1; i <= N; i++) 100 { 101 scanf("%lf", &val); 102 AddEdge(i+M, t, log(val)); 103 } 104 for(int i = 1; i <= L; i++) 105 { 106 int a, b; scanf("%d%d", &a, &b); 107 AddEdge(a, b+M, inf); 108 } 109 double flow = maxflow(); 110 printf("%.4lf ", exp(flow)); 111 } 112 return 0; 113 }