POJ 3308 Paratroopers

题目大意:

在一个n*m的格子地图上有l个外星人,有一种激光炮可以消灭他们,每当使用一次可以使某一行或某一列的外星人消失。但每使用一次都需要付一定的价钱。给出在每一行或每一列使用激光炮时需要的价格,问最少需要付多少才能消灭全部外星人。总价格是每一次使用价格的乘积。


解题思路:

这题看起来跟POJ3041差不多,但在这里增加了价格就不一样了。虽然建出来的图类似于一个二分图,但是在这里得用求最小割的办法来解决问题,也就建图的时候需要一个超级源点和超级汇点。

1、首先建图,超级汇点向坐标X依次建边,前向边的容量是在下表是X的那一行使用激光炮的价格取log(),(注1)后向边容量为零。同理建出向坐标Y到超级汇点的。

2、对于每一个外星人的坐标,建立相应X点到Y点的边,前向边容量无穷大,后向边容量为0。

3、然后使用Dinic算法求出最大流,也就是最小割容量。

4、用exp() 求出最小花费,


注意:

1、因为求最大流或者最小割是一个求和的过程,如果最小花费是乘积需要对数转化。

2、注意double的精度问题。



下面是代码:

#include <stdio.h>
#include <string.h>
#include <queue>
#include <math.h>
using namespace std;
const int inf=1e8;
const int Maxn=1005;
const double  eps = 0.00000001;

struct node
{
    int v,next;
    double w;
} edge[ Maxn*5];
int n,m,l,head[Maxn],cnt,deep[Maxn];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
double Eps(double x)
{
    return fabs(x)<eps?0:x;
}
double min(double a,double b)
{
    return a<b?a:b;
}
void addedge(int u,int v,double w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
    cnt++;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt;
    cnt++;
}
bool bfs()
{
    memset(deep,-1,sizeof(deep));
    queue <int > q;
    q.push(0);
    deep[0]=0;
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        int p=head[t];
        while(p!=-1)
        {
            int v=edge[p].v;
            if( deep[v]==-1&&Eps(edge[p].w)>0)
            {
                q.push(v);
                deep[v]=deep[t]+1;
            }
            p=edge[p].next;
        }
    }
    return deep[n+m+1]!=-1;
}
void does(int u,int v,double w)
{
    int p =head[u];
    while(edge[p].v!=v)
    {
        p=edge[p].next;
    }
    edge[p].w+=w;
}
double dfs(int src,double flow)
{
    if(src==n+m+1)return flow;
    double sum=0;
    int p=head[src];
    while(p!=-1)
    {
        int v=edge[p].v;
        if(deep[v]==deep[src]+1&&Eps(edge[p].w)>0)
        {
            double tmp=dfs(v,min(flow-sum,edge[p].w));
            sum+=tmp;
            edge[p].w-=tmp;
            does(v,src,tmp);
        }
        p=edge[p].next;
    }
    return sum;
}
double dinic()
{
    double ans=0;
    while(bfs())
    {
        ans+=dfs(0,inf);
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        double val;
        int u,v;
        init();
        scanf("%d%d%d",&n,&m,&l);
        for(int i=1; i<=n; i++)
        {
            scanf("%lf",&val);
            addedge(0,i,log(val));
        }
        for(int i=1; i<=m; i++)
        {
            scanf("%lf",&val);
            addedge(n+i,n+m+1,log(val));
        }
        for(int i=0; i<l; i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v+n,inf);
        }
        printf("%0.4f\n",exp(dinic()));
    }
    return 0;
}


POJ 3308 Paratroopers

上一篇:二逼事汇总 第3期


下一篇:循环赛日程表问题