poj3308 Paratroopers 最大流 最小点权覆盖

题意:有一个n*m的矩阵,告诉了在每一行或者每一列安装大炮的代价,每一个大炮可以瞬间消灭这一行或者这一列的所有敌人,然后告诉了敌人可能出现的L个坐标位置,问如何安置大炮,使花费最小。如果一个敌人位于第rc列,则他可以被第r行或者第c列的大炮消灭。

链接:http://poj.org/problem?id=3308

这题突然就让我想起来那个多校的那道多米诺骨牌的那个,几乎一样的模型,还不过要把权值改一下,因为权值是相乘,那么就吧权值改成相加,也就是用log去改变。

这样的话 如果坐标为x,y的点要被消灭,那么要么走x要么走y,这样的话就直接是一个二分图的形式了。一边是行,一边是列,用出现的点连边,就是最小点权模型,最小点权模型就是集合x点的点权做为s-x的边权(流量),y点的权值为y-t的边权,x-y的边权为无穷大,这样见图那么就可以用最大流搞。

这是我曾经看过的一个大神对于二分图边权覆盖的讲解。好像就是这道题。

求二分图顶点覆盖问题,都是转化为最小割问题去求解,转化方法如下:

建超级源S 和超级汇 T,假设二分图两个点集分别为 X 和 Y。X和Y原来的边容量设为INF,将S到X里每个点x连一条边,边权为x的点权,也可以看做覆盖点x的所有出边的花费(W-),将Y里每个点y到T连一条边,边权为y的点权,也可以看做覆盖点y的所有入边的花费(W+)。这样求得最小割容量,即为原问题的解。

/************这是对这个转化方法的解释和证明,有兴趣的同学可以看看************/

X到Y的边权为INF,自然不会成为最小割中的边,那就只有可能是S到X和Y到T中的边,而:S到X中点x的边e1, 权为点x的点权,点x和Y中的所有临边e2,都需要受到e1的流量的限制,同样,X到Y中点y的所有边也会受到点y到T的容量限制。这样求得割就能保证覆盖掉所有的边。

我们可以用反证法证明一下:假设有边<x, y>没有被覆盖掉,则边<S, x>流量为0且边<y, T>流量为0,而<x, y>流量为INF,自然可以找到一条S到T的增流路径<S, x, y, T>,与以求得流为最大流相矛盾,则可以说明,在最大流的情况下,所有的边都已经被覆盖掉。

而最小割问题可以用最大流来解决,问题就变得简单了。

/****************************************************************************/

  1 #include <stdio.h>
  2 #include <iostream>
  3 #include <queue>
  4 #include <string.h>
  5 #include <vector>
  6 #include <cmath>
  7 using namespace std;
  8 const double maxn = 1000000.0;
  9 int m,n,l;
 10 double row[110],col[105];
 11 struct edge
 12 {
 13     int u,v;
 14     double cap,flow;
 15 };
 16 vector<edge>edges;
 17 vector<edge>ed;
 18 vector<int>g[505],G[505];
 19 
 20 void addedge(int u,int v,double cap,double flow)
 21 {
 22     edges.push_back((edge){u,v,cap,flow});
 23     edges.push_back((edge){v,u,0,0});
 24     int m;
 25     m = edges.size();
 26     g[u].push_back(m-2);
 27     g[v].push_back(m-1);
 28 }
 29 
 30 void init(int n)
 31 {
 32     int i;
 33     for(i = 0;i <= n;i++)
 34     {
 35         g[i].clear();
 36     }
 37     edges.clear();
 38 }
 39 int vis[505],dis[505],cur[505];
 40 int bfs(int s,int t,int n)
 41 {
 42     memset(vis,0,sizeof(vis));
 43     queue<int>q;
 44     q.push(s);
 45     dis[s] = 0;
 46     vis[s] = 1;
 47 
 48     while(!q.empty())
 49     {
 50         int u,v;
 51         u = q.front();
 52         q.pop();
 53         for(int i = 0;i < g[u].size();i++)
 54         {
 55             edge &e = edges[g[u][i]];
 56             v = e.v;
 57             if(!vis[v] && e.cap-e.flow > 0)
 58             {
 59                 vis[v] = 1;
 60                 dis[v] = dis[u] +1;
 61                 q.push(v);
 62             }
 63         }
 64     }
 65     return vis[t];
 66 }
 67 double dfs(int u,double a,int t)
 68 {
 69     if(u == t || a == 0)
 70     return a;
 71     int v;
 72     double flow = 0,f;
 73     for(int& i = cur[u]; i < g[u].size();i++)
 74     {
 75         edge &e = edges[g[u][i]];
 76         v = e.v;
 77         if(dis[u]+1 == dis[v] &&(f = dfs(v,min(a,e.cap-e.flow),t)))
 78         {
 79             e.flow += f;
 80             edges[g[u][i]^1].flow -= f;
 81             flow += f;
 82             a -= f;
 83             if(a == 0)
 84             break;
 85         }
 86     }
 87 
 88     return flow;
 89 }
 90 double maxflow(int s,int t)
 91 {
 92     double flow = 0;
 93     while(bfs(s,t,t))
 94     {
 95         memset(cur,0,sizeof(cur));
 96         flow+=dfs(s,1000050,t);
 97     }
 98     return flow;
 99 }
100 
101 
102 int main()
103 {
104     int i,j;
105     int t;
106 
107     while(~scanf("%d",&t))
108     {
109         while(t--)
110         {
111             scanf("%d %d %d",&n,&m,&l);
112             init(n+m+2);
113 
114             for(i=1;i <= n;i++)
115             scanf("%lf",&row[i]);
116 
117             for(i = 1;i <= m;i++)
118             scanf("%lf",&col[i]);
119 
120             int u,v;
121 
122             for(i = 1;i <= n;i++)
123                 addedge(0,i,log(row[i]),0);
124             for(i = 1;i <= m;i++)
125                 addedge(n+i,n+m+1,log(col[i]),0);
126 
127             for(i = 1;i <= l;i++)
128             {
129                 int a,b;
130                 scanf("%d %d",&a,&b);
131                 addedge(a,n+b,maxn,0);
132             }
133 
134             double ans = maxflow(0,n+m+1);
135             printf("%.4f
",exp(ans));
136         }
137     }
138 
139     return 0;
140 }
View Code
原文地址:https://www.cnblogs.com/0803yijia/p/3256331.html