最大流最小割模型。
把问题转化成最小点权覆盖问题,就能用最小割求解。而最小割又和最大流是对偶问题,所以此题用dinic可解。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include<cmath>
#define INF 1000007
#define eps 1e-8
using namespace std;
int sta,end;
double val[200][200];
int tag[200];
int n,m,l;
double min(double a,double b)
{
return a>b?b:a;
}
bool bfs()
{
int u,v;
memset(tag,-1,sizeof(tag));
queue<int> q;
while (!q.empty())
q.pop();
q.push(sta);
tag[sta]=0;
while (!q.empty())
{
u=q.front();
q.pop();
for (v=sta; v<=end; v++)
{
if (tag[v] == -1 && val[u][v] > 0)
{
tag[v]=tag[u]+1;
q.push(v);
}
}
}
return tag[end] != -1;
}
double dfs(int u,double flow)
{
int v;
double td;
if (u == end)
return flow;
for (v=sta; v<=end; v++)
{
if (tag[u]+1 == tag[v] && val[u][v] > 0)
{
td=dfs(v,min(flow,val[u][v]));
if (td < eps)
continue;
val[u][v]-=td;
val[v][u]+=td;
return td;
}
}
return 0;
}
double dinic()
{
double res,ans;
ans=0.0;
while (bfs() == true)
{
while (true)
{
res=dfs(1,INF);
if (res < eps)
break;
ans+=res;
}
}
return ans;
}
int main()
{
int prob,i,j,t1,t2;
double td;
scanf("%d",&prob);
while (prob--)
{
scanf("%d%d%d",&m,&n,&l);
sta=1;
end=n+m+2;
memset(val,0,sizeof(val));
for (i=1; i<=m; i++)
{
scanf("%lf",&td);
val[sta][i+1]=log(td);
}
for (i=1; i<=n; i++)
{
scanf("%lf",&td);
val[i+m+1][end]=log(td);
}
for (i=1; i<=l; i++)
{
scanf("%d%d",&t1,&t2);
val[t1+1][t2+m+1]=INF;
}
printf("%.4f\n",exp(dinic()));
}
}