您的位置:首页 > 运维架构

pku 3308 Paratroopers

2010-10-06 16:50 218 查看
这是一道最小点覆盖问题,以前也做过类似的,但那道题没有权值,做法是点数减去二分图匹配数(如果构图时重复计算了,二分匹配数别忘了除2)。而这道题有权值,方法是加入超级源点和超级汇点,源点和所有行节点相连,所有列节点和汇点相连,权值为行或列的花费,如果a行b列有敌人,则把节点a和节点b相连,权值为无穷大。现在求源点和汇点之间的最小割,即最大流。

还有一个需要注意的地方是,这里问题是要求cost的乘积,可以通过使用log()把乘法先转换为加法,最后输出的时候再用exp()转换回去。

这道题还有几个地方把我恶心了,一是在精度控制上(cap[u][v]>flow[u][v]+1E-8),二是再g++中用printf时参数为lf有问题,要用f,vc++没有这个问题。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define HEAD 110
#define inf 100000000.0
using namespace std;

double cap[HEAD][HEAD],flow[HEAD][HEAD],a[HEAD];
int p[HEAD],q[10000],front,rear;

void Init()
{
memset(cap,0,sizeof(cap));
memset(flow,0,sizeof(flow));
}

double Edmonds(int s,int t,int n)
{
double f=0;
while(1)
{
memset(a,0,sizeof(a));
a[s]=inf;
front=rear=0;
q[++rear]=s;
while(front!=rear)
{
int u=q[++front];
for(int v=0;v<n;++v)
if((!a[v])&&cap[u][v]>flow[u][v]+1E-8)
{
p[v]=u;
q[++rear]=v;
a[v]=min(a[u],cap[u][v]-flow[u][v]);
}
}
if(fabs(a[t])<1E-8)
break;
for(int u=t;u!=s;u=p[u])
{
flow[p[u]][u]+=a[t];
flow[u][p[u]]-=a[t];
}
f+=a[t];
}
return f;
}

int main(void)
{
int row,col,poi,tol,a,b;
double res;
double temp;
scanf("%d",&tol);
while(tol--)
{
Init();
scanf("%d%d%d",&row,&col,&poi);
for(int i=1;i<=row;++i)
{
scanf("%lf",&temp);
cap[0][i]=log(temp);
}
int en=row+col+1;
for(int i=row+1;i<=row+col;++i)
{
scanf("%lf",&temp);
cap[i][en]=log(temp);
}
while(poi--)
{
scanf("%d%d",&a,&b);
cap[a][b+row]=inf;
}
res=Edmonds(0,en,en+1);
printf("%.4f/n",exp(res));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: