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

pku 3308 Paratroopers 最大流最小割

2012-07-21 10:21 465 查看
http://poj.org/problem?id=3308

题意:火星人要和地球人PK,地球人间谍搞到了一份情报:火星人要搞伞兵,登陆在地球一个row*col的地图上,而且知道伞兵的数量和每个伞兵要降落的格子。为了消灭敌人,可以在某一行或者某一列安置激光枪。每个激光枪可以瞬间消灭这一行(或者列)的敌人。

安装消灭第i行的激光枪消费是ri。

安装消灭第j行的激光枪消费是ci。

现在总部要你花费最小的费用,安装好足够的激光枪去消灭所有的火星人,问最小的花费是多少。

这里花费的定义有点不同:是每个激光器消费的乘积。

思路:最小割_最大流,把伞兵看成边,行列看成节点,转化为了带权二分图最小点覆盖。加入超级源点和超级汇点,源点和所有行节点相连(权值ri),所有列节点和汇点相连(权值ci),如果a行b列有敌人,则把节点a和节点b相连。则问题又可以转化求最小割。

因为对任一敌人<a,b>,必然有source-->a-->b-->sink,故路径上的三条边<source,a>, <a,b>, <b,sink>中至少有一条边在割中,我们把<a,b>的权值设置为无限大,则其不可能被选中。于是割边集中必然有<source,a>和<b,sink>中的至少一条,也即对应选择了相应的行或列,我们把这些边的权值设置为花费,则最小割即是总花费的最小方案。

最小割:对于图中的两个点(一般为源点和汇点)来说,如果把图中的一些边去掉,如果它们之间无法连通的话,则这些边组成的集合就叫为割了。如果这些边有权值,最小割就是指权值之和最小的一个割。

最大流最小割:应用于网络中,指总流量不超过链路可承载的最大值,且在每条子路径上取尽可能少的流量。对任意一个只有一个源点一个汇点的图来说,从源点到汇点的最大流等于最小割。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#define maxn 107
using namespace std;

const double inf = 99999999.0;
double c[maxn][maxn];
int level[maxn];
bool vt[maxn];
int n,m,l;
bool layer(int s,int e)
{
int i;
queue<int>q;
q.push(s);
memset(level,-1,sizeof(level));
level[s] = 1;
while (!q.empty())
{
int p = q.front(); q.pop();
for (i = s; i <= e; ++i)
{
if (c[p][i] && level[i] == -1)
{
level[i] = level[p] + 1;
if (i == e) return true;
q.push(i);
}
}
}
return false;
}
double dinic(int s,int e)
{
deque<int>q;
int pos,i,vs,ve;
double maxf = 0;
while (layer(s,e))
{
memset(vt,false,sizeof(vt));
q.push_back(s);
vt[s] = true;
while (!q.empty())
{
int p = q.back();
if (p == e)
{
double min = inf;
for (i = 1; i < q.size(); ++i)
{
vs = q[i - 1];
ve = q[i];
if (c[vs][ve] > 0 && min > c[vs][ve])
{
min = c[vs][ve];
pos = vs;
}
}
maxf += min;
for (i = 1; i < q.size(); ++i)
{
vs = q[i - 1];
ve = q[i];
if (c[vs][ve] > 0)
{
c[vs][ve] -= min;
c[ve][vs] += min;
}
}
while (!q.empty() && q.back() != pos)
{
vt[q.back()] = false;
q.pop_back();
}
}
else
{
for (i = s; i <= e; ++i)
{
if (c[p][i] > 0 && !vt[i] && level[i] == level[p] + 1)
{
vt[i] = true;
q.push_back(i);
break;
}
}
if (i > e) q.pop_back();
}

}
}
return maxf;
}
int main()
{
int i,x,y,s,e,t;
double val;
scanf("%d",&t);
while (t--)
{
memset(c,0,sizeof(c));
scanf("%d%d%d",&n,&m,&l);
s = 0; e = n + m + 1;
for (i = 1; i <= n; ++i)
{
scanf("%lf",&val);
c[s][i] = log(val);
}
for (i = 1; i <= m; ++i)
{
scanf("%lf",&val);
c[i + n][e] = log(val);
}
for (i = 1; i <= l; ++i)
{
scanf("%d%d",&x,&y);
c[x][y + n] = inf;
}
double ans = dinic(s,e);
printf("%.4lf\n",exp(ans));
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: