poj 3308 Paratroopers 最小割 最小点权覆盖

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 3308 Paratroopers 最小割 最小点权覆盖相关的知识,希望对你有一定的参考价值。

题目链接: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\n", exp(flow));
111     }
112     return 0;
113 }

 

以上是关于poj 3308 Paratroopers 最小割 最小点权覆盖的主要内容,如果未能解决你的问题,请参考以下文章

poj3308 Paratroopers --- 最小点权覆盖-&gt;最小割

poj 3308 Paratroopers(最小点权覆盖)

POJ 3308 最少点集覆盖

P3308 [SDOI2014]LIS(最小割+退流)

POJ 3308

POJ 1815 Friendship(最小割)