构建一个二分图,行坐标为S点集,纵坐标我T点集。令s=0,连接所有S,t=n+m+1,所有T连接t。
求此二分图的最小割,即最大流。
乘法需要 转换为 log()在求和,最后exp()回来
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
int n,m,l;
double cap[110][110],flow[110][110],a[110];
int pre[110];
double EK(int s,int t)
{
queue<int> q;
double f=0;
memset(flow,0,sizeof(flow));
memset(pre,0,sizeof(pre));
while(1){
q.push(s);
memset(a,0,sizeof(a));
a[s]=99999.0;
while(!q.empty()){
int u=q.front();
q.pop();
for(int v=0;v<=n+m+1;v++){
if(!a[v] && cap[u][v] > flow[u][v]){
pre[v]=u;
a[v]=min(a[u],cap[u][v]-flow[u][v]);
q.push(v);
}
}
}
if(a[t]==0) break;
for(int i=t;i!=s;i=pre[i]){
flow[pre[i]][i] += a[t];
flow[i][pre[i]] -= a[t];
}
f += a[t];
}
return exp(f);
}
int main()
{
int t;
int i,j,k,b,c;
double tt;
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&l);
memset(cap,0,sizeof(cap));
for(i=1;i<=n;i++){
scanf("%lf",&tt);
cap[0][i]=log(tt);
}
for(i=n+1;i<=n+m;i++){
scanf("%lf",&tt);
cap[i][n+m+1]=log(tt);
}
while(l--){
scanf("%d%d",&b,&c);
cap[b][c+n]=99999.0;
}
double ans=EK(0,n+m+1);
printf("%.4lf\n",ans);
}
}