首页 > 代码库 > zoj 2874 & poj 3308 Paratroopers (最小割)

zoj 2874 & poj 3308 Paratroopers (最小割)

题意:
一个m*n大小的网格,已知伞兵着陆的具体位置(行和列)。现在在某行(或某列)
安装一架激光枪,一架激光枪能杀死该行(或该列)所有的伞兵。在第i行安装一架
激光枪的费用是Ri,在第i列安装的费用是Ci。要安装整个激光枪系统,总费用为这些
激光枪费用的乘积。
求杀死所有伞兵的最小费用。



构图:
把伞兵视为边,行与列视为顶点。增加源点和汇点,对于第i行,从源点向顶点i连接一条
容量为Ri的边。对于第j列,从顶点j向汇点连接一条容量为Rj的边。
如果某一点(i,j)有伞兵降落,则从顶点Ri向顶点Cj连接一条容量为无穷大的边。


算法:
根据割的性质,源点和汇点必不连通,则割边必定在S->R,R->C,C->T其一。为了求得最小容量,
将R->C设为无穷大,则其不可能被选中。这样割边集为S-->R,C-->T的集合,也就是选中行或列。
此时求得的最小割为花费最小的方案。
由于花费为行和列的乘积,则通过对数运算把乘法转化为加法。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#define maxm 15000
#define maxn 105
#define eps 1e-6
using namespace std;

struct node
{
    int v,next;
    double val;
}e[maxm<<1];
int st,en,n,m,l,cnt;
int d[maxn];
int head[maxn],cur[maxn];
const double INF = 1000007;
queue<int> q;

void init()
{
    st = 0,en = n+m+1;
    memset(head,-1,sizeof(head));
    cnt = 0;
}
void add(int x,int y,double z)
{
    e[cnt].v = y;
    e[cnt].val = z;
    e[cnt].next = head[x];
    head[x]=cnt++;
    e[cnt].v = x;
    e[cnt].val = 0;
    e[cnt].next = head[y];
    head[y]=cnt++;
}
bool bfs()
{
    while(!q.empty())
        q.pop();
    memset(d,-1,sizeof(d));
    int u;
    d[st] = 0;
    q.push(st);
    while(!q.empty())
    {
        u = q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int t = e[i].v;
            if(e[i].val>0 && d[t]==-1)
            {
                d[t] = d[u]+1;
                q.push(t);
                if(t==en) return true;
            }
        }
    }
    return false;
}

double dfs(int x,double flow)
{
    if(x==en || fabs(flow)<=eps) return flow;
    double ret = 0,dd;
    for(int& i=cur[x];i!=-1;i=e[i].next)
    {
        int t = e[i].v;
        if(d[t] == d[x]+1 && (dd = dfs(t,min(flow,e[i].val)))>0)
        {
            e[i].val-=dd;
            e[i^1].val+=dd;
            flow-=dd;
            ret+=dd;
            if (fabs(flow) <= eps) break;
        }
    }
    return ret;
}
double Dinic()
{
    double tmp = 0,maxflow = 0;
    while(bfs())
    {
        for(int i=0;i<=en;i++)
            cur[i] = head[i];
        maxflow+=dfs(st,INF);
    }
    return maxflow;
}

int main()
{
    int T,a,b;
    double x;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&m,&n,&l);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%lf",&x);
            add(st,i,log(x));
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%lf",&x);
            add(i+m,en,log(x));
        }
        for(int i=1;i<=l;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b+m,INF);
        }
        printf("%.4f\n",exp(Dinic()));
    }
    return 0;
}