POJ_3308

这个题目有点像二分图最小点集覆盖问题,但由于边带权,所以不能直接用二分图最大匹配来做。

参考了别人的想法之后,发现构图的时候原来还是要用的二分图的思想,将行、列分别看做一个集合,由于最后求费用乘积的最小值,所以先传化成log2形式的费用,源点与行之间的容量初始化为log2行费用,列与汇点之间的容量初始化log2列费用。之后对读入的伞兵位置对应的行和列之间连一条有向边,容量为INF

    最后只要求一下最小割就可以了,也就是最大网络流。

#include<stdio.h>
#include
<string.h>
#include
<math.h>
double cap[110][110],flow[110][110],a[110];
int q[110],p[110];
int main()
{
int i,j,k,n,m,l,T,t,u,v,front,rear;
double f,temp;
scanf(
"%d",&T);
while(T--)
{
scanf(
"%d%d%d",&m,&n,&l);
t
=m+n+1;
for(i=0;i<=t;i++)
for(j=0;j<=t;j++)
{
cap[i][j]
=0.0;
flow[i][j]
=0.0;
}
for(i=1;i<=m;i++)
{
scanf(
"%lf",&temp);
cap[
0][i]=log2(temp);
}
for(i=m+1;i<t;i++)
{
scanf(
"%lf",&temp);
cap[i][t]
=log2(temp);
}
for(i=0;i<l;i++)
{
scanf(
"%d%d",&u,&v);
cap[u][m
+v]=1000000000.0;
}
f
=0;
while(1)
{
for(i=1;i<=t;i++)
a[i]
=0.0;
a[
0]=1000000000.0;
front
=rear=0;
q[rear
++]=0;
while(front<rear)
{
u
=q[front++];
for(v=0;v<=t;v++)
if(a[v]<1e-8&&cap[u][v]>flow[u][v])
{
temp
=cap[u][v]-flow[u][v];
a[v]
=a[u]<temp?a[u]:temp;
p[v]
=u;
q[rear
++]=v;
}
}
if(a[t]<1e-8)
break;
for(u=t;u!=0;u=p[u])
{
flow[p[u]][u]
+=a[t];
flow[u][p[u]]
-=a[t];
}
f
+=a[t];
}
printf(
"%.4f\n",pow(2,f));
}
return 0;
}
posted on 2011-08-07 14:31  Staginner  阅读(371)  评论(0编辑  收藏  举报