题意:一个矩阵,有的方格里有一些敌人,每行或每列都可以安放一架枪,每架枪都有一个花费,而且能消灭他所在的行或列的所有敌人,最后的花费为所有的枪花费的乘积。
乘积问题可以先取对数。转化成求和。
然后问题很像以前的一个二分匹配问题。把每一行加入到X集合。每一列加入到Y集合。则每一个外星人所在的(row,col)就连条边。求最小点覆盖。但是这个问题有权值。可以转化成KM或者最小割来求解。
最小割建图:
src 与每一行相连,权值为每行的花费。
en 与每一列相连,权值为每列花费。
假如外星人出现在(r,c)则连一条r -->c权值为inf的边。
1 // File Name: 3308.cpp 2 // Author: Missa 3 // Created Time: 2013/4/17 星期三 11:24:48 4 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 #include<cmath> 10 #include<queue> 11 #include<stack> 12 #include<string> 13 #include<vector> 14 #include<cstdlib> 15 #include<map> 16 #include<set> 17 using namespace std; 18 #define CL(x,v) memset(x,v,sizeof(x)); 19 #define R(i,st,en) for(int i=st;i<en;++i) 20 #define LL long long 21 22 const double eps = 1e-6; 23 const int inf = 0x3f3f3f3f; 24 const int maxn = 100+5; 25 const int maxm = 15000; 26 struct Edge 27 { 28 int v, next; 29 double c; 30 }p[maxm << 1]; 31 int head[maxn], e; 32 int d[maxn], cur[maxn]; 33 int n, m, st, en; 34 void init() 35 { 36 e = 0; 37 //n = en;//记住n赋值为点的个数 38 memset(head, -1, sizeof(head)); 39 } 40 void addEdge(int u, int v, double c) 41 { 42 p[e].v = v; p[e].c = c; 43 p[e].next = head[u]; head[u] = e++; 44 swap(u,v); 45 p[e].v = v; p[e].c = 0; 46 p[e].next = head[u]; head[u] = e++; 47 } 48 int bfs(int st, int en) 49 { 50 queue <int > q; 51 memset(d, 0, sizeof(d)); 52 d[st] = 1; 53 q.push(st); 54 while (!q.empty()) 55 { 56 int u = q.front();q.pop(); 57 for (int i = head[u]; i != -1; i = p[i].next) 58 { 59 if (p[i].c > 0 && !d[p[i].v]) 60 { 61 d[p[i].v] = d[u] + 1; 62 q.push(p[i].v); 63 } 64 } 65 } 66 return d[en]; 67 } 68 double dfs(int u, double a) 69 { 70 if (u == en || fabs(a) <= eps) return a; 71 double f, flow = 0; 72 for (int& i = cur[u]; i != -1; i = p[i].next) 73 { 74 if (d[u] + 1 == d[p[i].v] && (f = dfs(p[i].v, min(a, p[i].c))) > 0) 75 { 76 p[i].c -= f; 77 p[i^1].c += f; 78 flow += f; 79 a -= f; 80 if (fabs(a) <= eps) break; 81 } 82 } 83 return flow; 84 } 85 double dinic(int st, int en) 86 { 87 double ret = 0, tmp; 88 while (bfs(st, en)) 89 { 90 for (int i = 0; i <= n; ++i) 91 cur[i] = head[i]; 92 ret += dfs(st, inf); 93 } 94 return ret; 95 } 96 int row, col, le; 97 int main() 98 { 99 int cas; 100 double c; 101 scanf("%d", &cas); 102 while (cas--) 103 { 104 init(); 105 scanf("%d%d%d", &row, &col, &le); 106 st = 0, en = row + col + 1; 107 n = en; 108 for (int i = 1; i <= row; ++i) 109 { 110 scanf("%lf", &c); 111 addEdge(st, i, log(c)); 112 } 113 for (int i = 1; i <= col; ++i) 114 { 115 scanf("%lf", &c); 116 addEdge(i + row, en, log(c)); 117 } 118 while (le--) 119 { 120 int u, v; 121 scanf("%d%d",&u, &v); 122 addEdge(u, v + row, inf); 123 } 124 printf("%.4f\n",exp(dinic(st, en))); 125 } 126 return 0; 127 }