pku 3308 Paratroopers 最大流最小割

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

题意:火星人要和地球人PK,地球人间谍搞到了一份情报:火星人要搞伞兵,登陆在地球一个row*col的地图上,而且知道伞兵的数量和每个伞兵要降落的格子。为了消灭敌人,可以在某一行或者某一列安置激光枪。每个激光枪可以瞬间消灭这一行(或者列)的敌人。

安装消灭第i行的激光枪消费是ri。

安装消灭第j行的激光枪消费是ci。

现在总部要你花费最小的费用,安装好足够的激光枪去消灭所有的火星人,问最小的花费是多少。

这里花费的定义有点不同:是每个激光器消费的乘积。

思路:最小割_最大流,把伞兵看成边,行列看成节点,转化为了带权二分图最小点覆盖。加入超级源点和超级汇点,源点和所有行节点相连(权值ri),所有列节点和汇点相连(权值ci),如果a行b列有敌人,则把节点a和节点b相连。则问题又可以转化求最小割。

因为对任一敌人<a,b>,必然有source-->a-->b-->sink,故路径上的三条边<source,a>, <a,b>, <b,sink>中至少有一条边在割中,我们把<a,b>的权值设置为无限大,则其不可能被选中。于是割边集中必然有<source,a>和<b,sink>中的至少一条,也即对应选择了相应的行或列,我们把这些边的权值设置为花费,则最小割即是总花费的最小方案。

 

最小割:对于图中的两个点(一般为源点和汇点)来说,如果把图中的一些边去掉,如果它们之间无法连通的话,则这些边组成的集合就叫为割了。如果这些边有权值,最小割就是指权值之和最小的一个割。

最大流最小割:应用于网络中,指总流量不超过链路可承载的最大值,且在每条子路径上取尽可能少的流量。对任意一个只有一个源点一个汇点的图来说,从源点到汇点的最大流等于最小割。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#define maxn 107
using namespace std;

const double inf = 99999999.0;
double c[maxn][maxn];
int level[maxn];
bool vt[maxn];
int n,m,l;
bool layer(int s,int e)
{
    int i;
    queue<int>q;
    q.push(s);
    memset(level,-1,sizeof(level));
    level[s] = 1;
    while (!q.empty())
    {
        int p = q.front(); q.pop();
        for (i = s; i <= e; ++i)
        {
            if (c[p][i] && level[i] == -1)
            {
                level[i] = level[p] + 1;
                if (i == e) return true;
                q.push(i);
            }
        }
    }
    return false;
}
double dinic(int s,int e)
{
    deque<int>q;
    int pos,i,vs,ve;
    double maxf = 0;
    while (layer(s,e))
    {
        memset(vt,false,sizeof(vt));
        q.push_back(s);
        vt[s] = true;
        while (!q.empty())
        {
            int p = q.back();
            if (p == e)
            {
                double min = inf;
                for (i = 1; i < q.size(); ++i)
                {
                    vs = q[i - 1];
                    ve = q[i];
                    if (c[vs][ve] > 0 && min > c[vs][ve])
                    {
                        min = c[vs][ve];
                        pos = vs;
                    }
                }
                maxf += min;
                for (i = 1; i < q.size(); ++i)
                {
                     vs = q[i - 1];
                     ve = q[i];
                    if (c[vs][ve] > 0)
                    {
                        c[vs][ve] -= min;
                        c[ve][vs] += min;
                    }
                }
                while (!q.empty() && q.back() != pos)
                {
                    vt[q.back()] = false;
                    q.pop_back();
                }
            }
            else
            {
                for (i = s; i <= e; ++i)
                {
                    if (c[p][i] > 0 && !vt[i] && level[i] == level[p] + 1)
                    {
                        vt[i] = true;
                        q.push_back(i);
                        break;
                    }
                }
                if (i > e) q.pop_back();
            }

        }
    }
    return maxf;
}
int main()
{
    int i,x,y,s,e,t;
    double val;
    scanf("%d",&t);
    while (t--)
    {
        memset(c,0,sizeof(c));
        scanf("%d%d%d",&n,&m,&l);
        s = 0; e = n + m + 1;
        for (i = 1; i <= n; ++i)
        {
            scanf("%lf",&val);
            c[s][i] = log(val);
        }
        for (i = 1; i <= m; ++i)
        {
            scanf("%lf",&val);
            c[i + n][e] = log(val);
        }
        for (i = 1; i <= l; ++i)
        {
            scanf("%d%d",&x,&y);
            c[x][y + n] = inf;
        }
        double ans = dinic(s,e);
        printf("%.4lf\n",exp(ans));
    }
    return 0;
}

  

posted @ 2012-07-21 10:21  E_star  阅读(343)  评论(0编辑  收藏  举报