• 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
  • 相关阅读:
    多值参数
    TK图形界面
    匿名函数
    try -catch-finally一些要点
    C#枚举类型转换
    Linux下查看MySQL的安装路径
    linux安装oracle 报错[INS-20802] Oracle Net Configuration Assistant failed 解决办法
    suse-Linux下安装Oracle11g服务器
    window7 下安卓开发环境搭建
    学习Linux最简单的方法
  • 原文地址:https://www.cnblogs.com/0803yijia/p/3256331.html
Copyright © 2020-2023  润新知