题目链接 http://poj.org/problem?id=3308
题目大意:球人和火星人开战了,现在有一个m*n大的地方,而有l个火星降落伞员要降落此地,为了不让一个火星人落下,地球人用了激光炮,这些激光炮一个能消灭一行或一列,当然,这是有消耗的,问,怎么让消耗最小。(消耗的大小为激光炮的代价的乘积)
题目分析:二分图-----最小点权覆盖----最小割-----最大流 参见amber论文《最小割模型在信息学竞赛中的应用》 将每行与起点相连,然后代价为该行的代价,同理 每列与终点相连 代价为该列的代价 某点有伞兵降落,则将该行与该列相连 代价为inf 则就转化为在这个图上求一个最小割的,即求这个图的最大流
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<cmath>
#define N 110
#define CC(x,y) memset(x,y,sizeof(x))
#define inf 1e8
using namespace std;
struct node
{
int x,y,ne;
double f;
}e[N*N];
int dis[N],pre[N],cur[N],h[N],gap[N],s,t,nn,i,j,k,m,n,x,y,z,l;
void add(int x,int y,double f)
{
e[k].y=y;e[k].f=f;e[k].ne=h[x];h[x]=k++;
e[k].y=x;e[k].f=0;e[k].ne=h[y];h[y]=k++;
}
double sap()
{
for (i=0;i<=nn;i++)
{
cur[i]=h[i];
gap[i]=dis[i]=0;
}
int u,v;
double flow=0,aug=inf;
gap[s]=nn;
u=pre[s]=s;
bool flag;
while(dis[s]<nn)
{
flag=0;
for(int &j=cur[u]; j!=-1; j=e[j].ne)
{
int v=e[j].y;
if(e[j].f>0&&dis[u]==dis[v]+1)
{
flag=1;
if(e[j].f<aug) aug=e[j].f;
pre[v]=u;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
e[cur[u]].f-=aug;
e[cur[u]^1].f+=aug;
}
aug=inf;
}
break;
}
}
if(flag)
continue;
int mindis=nn;
for(int j=h[u]; j!=-1; j=e[j].ne)
{
int v=e[j].y;
if(e[j].f>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int main()
{
//freopen("in.txt","r",stdin);
int tt;
scanf("%d",&tt);
while (tt--)
{
scanf("%d%d%d",&m,&n,&l);
s=0;t=n+m+1;nn=t+1;
double r;
CC(h,-1);
k=0;
for (i=1;i<=m;i++)
{
scanf("%lf",&r);
r=log(r);
add(s,i,r);
}
for (i=1;i<=n;i++)
{
scanf("%lf",&r);
r=log(r);
add(i+m,t,r);
}
for (i=1;i<=l;i++)
{
scanf("%d%d",&x,&y);
add(x,y+m,inf);
}
double flow=sap();
printf("%.4lf\n",exp(flow));
}
}