题目链接:http://poj.org/problem?id=3308
题意:外星人来攻打地球了。。。外星人派了一些伞兵来攻占地球的兵工场,兵工厂是一个矩形网格,伞兵会降落在兵工厂的某个位置。地球人有激光武器,可以杀死一行或者一列的所有敌人。但是每个激光武器安置在每行每列的费用都是不同的。伞兵很厉害只要一个就可以消灭兵工厂,所以,现在要部署一套激光系统使得伞兵一降落就可以消灭所有敌人。并且要求费用最少。
题解:
每个伞兵要用安置在其行上或者其列上的激光武器消灭。将矩阵的每行每列都视为一个点,将源点与“行点”相连,将汇点与“列点”相连对于伞兵降落的某个位置,将其行点和列点连接。根据割的性质,源点与汇点必不连通,因此割边集中必定存在S->R、R->C、C->T 其一。为了求得最小容量,将R->C 的容量设为无穷大,则其不可能被选中。这样割边集为S->R 与C->T的集合,也就是选中了行或列。此时求得的最小割即为花费最小的方案。
注意:1.花费是权值的乘积,可以用log和exp转化为加的形式。2.double的精度问题,据说有个2被原则,即eps取保留位数的2倍,所以取1e-8。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int MAXN=500+50*2+10;
const double INF=1e8;
const double eps=1e-8;
double g[MAXN][MAXN];
int level[MAXN];
int cur[MAXN];
int N,S,E;
double precision(double x)
{
return fabs(x)<eps?0:x;
}
int BFS()
{
memset(level,-1,sizeof(level));
level[S]=0;
queue<int>que;
que.push(S);
while(!que.empty())
{
int u=que.front();
que.pop();
for(int v=0;v<N;v++)
{
if(level[v]<0&&precision(g[u][v])>0.0)
{
level[v]=level[u]+1;
que.push(v);
}
}
}
if(level[E]>0) return 1;
return 0;
}
double DFS(int x,double low)
{
if(x==E) return low;
for(int i=cur[x];i<N;i++)
{
cur[x]=i;
if(precision(g[x][i])>0.0&&level[i]==level[x]+1)
{
double a=DFS(i,min(low,g[x][i]));
if(precision(a)>0.0)
{
g[x][i]-=a;
g[i][x]+=a;
return a;
}
}
}
return 0;
}
double Dinic()
{
double ans=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
double tans;
while(tans=DFS(S,INF)) ans+=tans;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int tcase;
scanf("%d",&tcase);
while(tcase--)
{
int m,n,l;
scanf("%d%d%d",&m,&n,&l);
N=m+n+2;
S=0;E=N-1;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
g[i][j]=0.0;
}
for(int i=1;i<=m;i++)
{
double val;
scanf("%lf",&val);
g[S][i]=log(val);
}
for(int i=1;i<=n;i++)
{
double val;
scanf("%lf",&val);
g[m+i][E]=log(val);
}
for(int i=1;i<=l;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g[x][m+y]=INF;
}/*
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
cout<<g[i][j]<<" ";
cout<<endl;
}*/
printf("%.4lf\n",exp(Dinic()));
}
return 0;
}