二分图最小点权覆盖。
代码:
#include<iostream>
#include<fstream>
#include<queue>
#include<cmath>
using namespace std;
int n;
int d[110];
double flow;
int v[110];
typedef struct e{
int data;
double f,c;
e *next,*opt;
}e;
e edge[110];
int build(){
int i,j,k;
queue<int> q;
q.push(1);
memset(d,0,sizeof(d));
d[1]=1;
while(!q.empty())
{
i=q.front();
q.pop();
e *p=edge[i].next;
while(p)
{
j=p->data;
if(d[j]==0&&p->c>p->f)
{
d[j]=d[i]+1;
if(j==n) return 1;
q.push(j);
}
p=p->next;
}
}
return 0;
}
double find(int m,double minw){
int i,k;
double j;
if(m==n) return minw;
v[m]=1;
e *p=edge[m].next;
while(p)
{
i=p->data;
if(p->c>p->f&&d[i]==d[m]+1&&v[i]==0)
{
j=find(i,min(minw,p->c-p->f));
if(j)
{
p->f+=j;
p->opt->f=p->f*(-1);
return j;
}
}
p=p->next;
}
return 0;
}
double solve(){
int j;
double k;
flow=0;
double i;
while(build())
while(1){
memset(v,0,sizeof(v));
i=10000000;
k=find(1,i);
flow+=k;
if(k==0) break;
}
return flow;
}
void read(){
// ifstream cin("in.txt");
int i,j,k,s,t,m;
double value;
int K;
cin>>K;
while(K--)
{
memset(edge,0,sizeof(edge));
cin>>n>>m>>k;
for(i=1;i<=n;i++)
{
cin>>value;
e *p=new e;
p->data=i+1;
p->next=edge[1].next;
edge[1].next=p;
p->c=log(value);
p->f=0;
e *q=new e;
q->data=1;
q->next=edge[i+1].next;
edge[i+1].next=q;
q->c=q->f=0;
p->opt=q;
q->opt=p;
}
for(i=1;i<=m;i++)
{
cin>>value;
e *p=new e;
p->data=i+n+1;
p->next=edge[n+m+2].next;
edge[n+m+2].next=p;
p->c=0;
p->f=0;
e *q=new e;
q->data=n+m+2;
q->next=edge[i+1+n].next;
edge[i+1+n].next=q;
q->f=0;q->c=log(value);
p->opt=q;
q->opt=p;
}
for(i=1;i<=k;i++)
{
cin>>s>>t;
e *p=new e;
p->data=t+1+n;
p->next=edge[1+s].next;
edge[1+s].next=p;
p->c=10000000;
p->f=0;
e *q=new e;
q->data=1+s;
q->next=edge[t+n+1].next;
edge[t+n+1].next=q;
q->c=q->f=0;
p->opt=q;
q->opt=p;
}
n+=2+m;
solve();
printf("%.4lf\n",exp(flow));
}
}
int main(){
read();
return 0;
}