POJ 3308 Paratroopers

来源:互联网 发布:手机文件传输软件 编辑:程序博客网 时间:2024/05/16 06:27

题目大意:

在一个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;}


0 0
原创粉丝点击