其实最开始看没啥思路,还以为是DP什么的。冷静分析一下,我们可以把横竖行分开来看,那么有一个伞兵就在左右脸上一条线(流量无穷),这不是个二分图吗?!
然后就很自然想到加上一个源点一个汇点就成了网络流求最小割,也就是最大流的问题上来。NICE。
#include "stdio.h"
#include "iostream"
#include "stdlib.h"
#include "queue"
#include "math.h"
#include "string.h"
using namespace std;
double row[150][150],flow[150];
int pre[150];
double bfs(int beg,int end)
{
queue<int> Q;
int i,j,k;
for(i=0;i<=end;i++)
{
pre[i]=-1;
}
pre[beg]=0;
flow[beg]=99999999.0;
while(!Q.empty())
{
Q.empty();
}
Q.push(beg);
while(!Q.empty())
{
k=Q.front();
Q.pop();
if(k == end) break;
for(i=0;i<=end;i++)
{
if(i!=beg && row[k][i]>0 && pre[i]==-1)
{
pre[i]=k;
flow[i]=min(flow[k],row[k][i]);
Q.push(i);
}
}
}
if(pre[end] == -1) return -1;
else return flow[end];
}
double maxflow(int beg,int end)
{
int sta,des;
double increase,sum=0.0;
while((increase=bfs(beg,end))!=-1)
{
des=end;
while(des!=beg)
{
sta=pre[des];
row[sta][des]-=increase;
row[des][sta]+=increase;
des=sta;
}
sum+=increase;
}
return sum;
}
int main()
{
int T,m,n,l,x,y,i;
double c;
scanf("%d",&T);
while(T--)
{
scanf("%d %d %d",&m,&n,&l);
int mn=m+n+1;
memset(row,0,sizeof(row));
for(i=1;i<=m;i++)
{
scanf("%lf",&row[0][i]);
row[0][i]=log(row[0][i]);
}
for(i=m+1;i<mn;i++) //注意这里i的初始化
{
scanf("%lf",&row[i][mn]);
row[i][mn]=log(row[i][mn]);
}
for(i=1;i<=l;i++)
{
scanf("%d %d",&x,&y);
row[x][y+m]=999999999.0;
}
printf("%.4lf\n",exp(maxflow(0,mn))); //Dinic算法就可以了以上可以作为一个模板了
}
}