poj 3308

题意:一个矩阵,有的方格里有一些敌人,每行或每列都可以安放一架枪,每架枪都有一个花费,而且能消灭他所在的行或列的所有敌人,最后的花费为所有的枪花费的乘积。

乘积问题可以先取对数。转化成求和。

然后问题很像以前的一个二分匹配问题。把每一行加入到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 }

 

 

你可能感兴趣的:(poj)