POJ 3308 Paratroopers

题意:火星人要攻打地球,火星人将派来一些伞兵来破坏军事设施。已知他们将降落在一个矩阵行的地区,而且知道这些人会降落在哪一行那一列。现在地球人可以造一些大炮来攻击他们,一门大炮可以攻击一行或者一列,一个伞兵只要被他所在的行或列的大炮打中他就会挂,而在每一行、每一列造大炮的价格是不同的,建造大炮总价格等于你选择在某行或某列造大炮价格的乘积。现在要求把所有的伞兵都搞挂了并且让这个价格尽可能的小。

看到乘积尽量小,想到了取对数。那么剩下的问题就是二分图点权覆盖的问题了。最后求完最大流之后,再还原这个费用就可以了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn = 110;
 7 const int maxm = 10000;
 8 const double inf = 1e8;
 9 int v[maxm],next[maxm];
10 double w[maxm];
11 int first[maxn],d[maxn],work[maxn],q[maxn];
12 int e,S,T;
13 
14 void init(){
15     e = 0;
16     memset(first,-1,sizeof(first));
17 }
18 
19 void add_edge(int a,int b,double c){
20     //printf("add:%d to %d,cap = %.4f\n",a,b,c);
21     v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++;
22     v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++;
23 }
24 
25 int bfs(){
26     int rear = 0;
27     memset(d,-1,sizeof(d));
28     d[S] = 0;q[rear++] = S;
29     for(int i = 0;i < rear;i++){
30         for(int j = first[q[i]];j != -1;j = next[j])
31             if(w[j] && d[v[j]] == -1){
32                 d[v[j]] = d[q[i]] + 1;
33                 q[rear++] = v[j];
34                 if(v[j] == T)   return 1;
35             }
36     }
37     return 0;
38 }
39 
40 double dfs(int cur,double a){
41     if(cur == T)    return a;
42     for(int &i = work[cur];i != -1;i = next[i]){
43         if(w[i] && d[v[i]] == d[cur] + 1)
44             if(double t = dfs(v[i],min(a,w[i]))){
45                 w[i] -= t;w[i^1] += t;
46                 return t;
47             }
48     }
49     return 0;
50 }
51 
52 double dinic(){
53     double ans = 0;
54     while(bfs()){
55         memcpy(work,first,sizeof(first));
56         while(double t = dfs(S,inf))    ans += t;
57     }
58     return ans;
59 }
60 
61 int main()
62 {
63     int kase,m,n,l;
64     scanf("%d",&kase);
65     while(kase--){
66         init();
67         scanf("%d%d%d",&m,&n,&l);
68         S = 0,T = m+n+1;
69         for(int i = 1;i <= m;i++){
70             double c;
71             scanf("%lf",&c);
72             add_edge(S,i,log(c));
73         }
74         for(int i = m+1;i <= m+n;i++){
75             double c;
76             scanf("%lf",&c);
77             add_edge(i,T,log(c));
78         }
79         for(int i = 0;i < l;i++){
80             int a,b;
81             scanf("%d%d",&a,&b);
82             add_edge(a,b+m,inf);
83         }
84         double ans = dinic();
85         printf("%.4f\n",exp(ans));
86     }
87     return 0;
88 }
View Code

 

posted @ 2013-11-12 19:13  浙西贫农  阅读(126)  评论(0编辑  收藏  举报