poj3308 Paratroopers --- 最小点权覆盖->最小割

题目是一个非常明显的二分图带权匹配模型,

加入源点到nx建边,ny到汇点建边,(nx。ny)=inf建边。求最小割既得最小点权覆盖。

在本题中因为求的是乘积,所以先所有取log转换为加法,最后再乘方回来。


#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#define eps 1e-6
#define ll __int64
const int maxn=110;
using namespace std;

int n,s,t,level[maxn];
double c[maxn][maxn];

bool makelevel()
{
    memset(level,0,sizeof level);
    level[s]=1;
    int q[maxn];
    int fro=0,iq=0;
    q[iq++]=s;
    int i,v;
    while(fro!=iq)
    {
        v=q[fro++];
        for(i=0;i<=t;i++)
        {
            if(!level[i]&&c[v][i])
            {
                level[i]=level[v]+1;
                q[iq++]=i;
            }
        }
    }
    if(!level[t]) return 0;
    return 1;
}

double dfs(int now,double maxf)
{
    if(now==t) return maxf;
    double ret=0;
    for(int i=0;maxf!=0&&i<=t;i++)
    {
        if(c[now][i]&&level[now]+1==level[i])
        {
            double tmp=dfs(i,min(maxf,c[now][i]));
            c[now][i]-=tmp;
            c[i][now]+=tmp;
            ret+=tmp;
            maxf-=tmp;
        }
    }
    return ret;
}

double dinic()
{
    double ans=0;
    while(makelevel()) ans+=dfs(s,10000000);
    return ans;
}

int main()
{
    int icy,m,l,i,aa,bb;
    double a,b;
    scanf("%d",&icy);
    while(icy--)
    {
        scanf("%d%d%d",&m,&n,&l);
        s=0;t=n+m+1;
        memset(c,0,sizeof c);
        for(i=1;i<=m;i++)
        {
            scanf("%lf",&a);
            c[0][i]=log(a);
        }
        for(i=1;i<=n;i++)
        {
            scanf("%lf",&a);
            c[i+m][t]=log(a);
        }
        for(i=0;i<l;i++)
        {
            scanf("%d%d",&aa,&bb);
            c[aa][bb+m]=10000000;
        }
        printf("%.4lf\n",exp(dinic()));
    }
    return 0;
}


你可能感兴趣的:(poj3308 Paratroopers --- 最小点权覆盖->最小割)