//题目类型:最大流最小割
解题思路:把伞兵看成边,行列看成节点,转化为了带权二分图最小点覆盖。
加入超级源点和超级汇点,源点和所有行节点相连,所有列节点和汇点相连,如果a行b列有敌人,则把节点a和节点b相连。则问题又可以转化求最小割。
现在求源点和汇点之间的最小割。因为对任一敌人<a,b>,必然有source-->a-->b-->sink, 割的性质是"不存在一条从source到sink的路径", 故路径上
的三条边<source,a>, <a,b>, <b,sink>中至少有一条边在割中,我们把<a,b>的权值设置为无限大,则其不可能被选中。于是割边集中必然有<source,a>
和<b,sink>中的至少一条,也即对应选择了相应的行或列,我们把这些边的权值设置为花费,则最小割即是总花费的最小方案。还有一个需要注意的地方
是,这里问题是要求cost的乘积,可以通过使用log()把乘法先转换为加法,最后输出的时候再转换回去。
题目分析转载自:http://blog.csdn.net/logic_nut/archive/2009/08/29/4496579.aspx
#include <iostream>
//#include <conio.h>
#include <queue>
#include <math.h>
using namespace std;
#define nodearray 110
const int INF = 1000000;
int m,n,l;
double capacity[nodearray][nodearray];
int d[nodearray]; //标号
int num[nodearray]; //num[i]表示标号为i的顶点数有多少
int pre[nodearray]; //记录前驱
int vn;
void ini_d(int src,int des) //BFS计算标号,汇点t标号为0
{
int k;
queue<int>Q;
memset(d,1,sizeof(d));
memset(num,0,sizeof(num));
Q.push(des);
d[des]=0; //汇点的标号为0
num[0]=1;
while (!Q.empty())
{
k=Q.front(),Q.pop();
for (int i=0;i<vn;i++) //遍历所有的结点
{
if (d[i]>=vn&&capacity[i][k]>0) //此处要特别注意,通过frontint的值改变其他的距离标号
{
d[i]=d[k]+1;
Q.push(i);
num[d[i]]++;
}
}
}
}
int findAlowArc(int i) //从i出发寻找允许弧
{
int j;
for (j=0;j<vn;j++) if (capacity[i][j]>0&&d[i]==d[j]+1) return j;
return -1;
}
int reLable(int i) //重新标号
{
int mm=INF;
for (int j=0;j<vn;j++)
if (capacity[i][j]>0) mm=min(mm,d[j]+1);
return mm==INF?vn:mm;
}
double maxFlow(int s,int t) //从源点s出发的最大流
{
double flow=0;
int i=s,j;
double delta; //增量
memset(pre,-1,sizeof(pre));
while (d[s]<vn)
{
j=findAlowArc(i);
if (j>=0)
{
pre[j]=i;
i=j; //从前往后找
if (i==t) //更新残留网络
{
delta=INF;
for (i=t;i!=s;i=pre[i]) delta=min(delta,capacity[pre[i]][i]); //找到增广路径的增量
for (i=t;i!=s;i=pre[i]) capacity[pre[i]][i] -= delta, capacity[i][pre[i]] += delta; //更改流量
flow += delta;
}
}
else
{
int x=reLable(i); //重新标号
num[x]++;
num[d[i]]--;
if (num[d[i]]==0) return flow; //间隙优化
d[i]=x;
if (i!=s) i=pre[i];
}
}
return flow;
}
int main()
{
//freopen("1.txt","r",stdin);
int i,j;
int a,b;
int src,des;
int t;
double cost;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&l);
src = 0;
des = m+n+1;
vn = m+n+2;
memset(capacity,0,sizeof(capacity));
for(i=1;i<=m;++i)
{
scanf("%lf",&cost);
capacity[src][i]=log(cost);
}
for(i=1;i<=n;++i)
{
scanf("%lf",&cost);
capacity[m+i][des]=log(cost);
}
for(i=1;i<=l;++i)
{
scanf("%d%d",&a,&b);
capacity[a][b+m]=INF;
}
ini_d(src,des);
printf("%.4lf\n",exp(maxFlow(src,des)));
}
//getch();
return 0;
}