ACM: 图论题 poj 3308 最大流问题
2016-05-19 23:26
459 查看
Paratroopers
Description
It is year 2500 A.D. and there is a terrible war between the
forces of the Earth and the Mars. Recently, the commanders of the
Earth are informed by their spies that the invaders of Mars want to
land some paratroopers in the m × n grid yard of one
their main weapon factories in order to destroy it. In addition,
the spies informed them the row and column of the places in the
yard in which each paratrooper will land. Since the paratroopers
are very strong and well-organized, even one of them, if survived,
can complete the mission and destroy the whole factory. As a
result, the defense force of the Earth must kill all of them
simultaneously after their landing.
In order to accomplish this task, the defense force wants to
utilize some of their most hi-tech laser guns. They can install a
gun on a row (resp. column) and by firing this gun all paratroopers
landed in this row (resp. column) will die. The cost of installing
a gun in the ith row (resp. column) of the grid yard is
ri (resp. ci ) and the total
cost of constructing a system firing all guns simultaneously is
equal to the product of their costs. Now, your team as a high rank
defense group must select the guns that can kill all paratroopers
and yield minimum total cost of constructing the firing system.
Input
Input begins with a number T showing the number of test
cases and then, T test cases follow. Each test case begins
with a line containing three integers 1 ≤ m ≤ 50 , 1 ≤
n ≤ 50 and 1 ≤ l ≤ 500 showing the number of rows and
columns of the yard and the number of paratroopers respectively.
After that, a line with m positive real numbers greater or
equal to 1.0 comes where the ith number is
ri and then, a line with n positive real
numbers greater or equal to 1.0 comes where the ith number
is ci. Finally, l lines come each
containing the row and column of a paratrooper.
Output
For each test case, your program must output the minimum total
cost of constructing the firing system rounded to four digits after
the fraction point.
Sample Input
1
4 4 5
2.0 7.0 5.0 2.0
1.5 2.0 2.0 8.0
1 1
2 2
3 3
4 4
1 4
Sample Output
16.0000
题意: 地球和火星发生战争, 火星派特工来偷袭地球的武器, 因为火星特工很厉害, 只要一个
生存下来就可以破坏全部. 现在要消灭全部特工, 有消息获得每个特工的降落位置(x,y);
地球用激光枪消灭, 每建造一个可以消灭整行或整列, 但是每行每列的造价不一样, 要求
用最少费用消灭全部敌人. 造价是全部激光枪的费用的乘积.(这里怪怪: product).
解题思路:
1.
题目其实不难, 仔细分析问题: 尽可能用最小费用, 消灭最多的敌人. 每次行列交叉,
都有2个选择. 就像选择路径一样, 但是路径上的敌人会随着你的选择而改变. 图论
中网络流问题. 路径上有容量 和 流量.
2. 果断建图:
设超级源点start = 0, 每行1~n节点X集合, 每列n+1~n+m节点Y集合.
超级汇点end = n+m+1;
从start到X集合的权值(每行费用)表示容量, X集合到Y集容量为INF(无限大), Y集合
到end的权值(每列的费用)表示容量. 样例建图如下图 :
![](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
因为结果要求乘积, 费用就用以10为底的对数表示方便加法, 最后exp转换回来即可.
3.
剩下就是求出网络流-最大流, 每条路径最用最小费用限制了, 这样结果最大流就是
消灭全部敌人最小费用. KM算法(增广路算法)即可.
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define MAX 1005
const int INF = (1<<29);
int n, m, L, p[MAX];
double cap[MAX][MAX], flow[MAX][MAX], a[MAX];
int start, end, M;
inline double min(double a, double b)
{
return a < b ? a : b;
}
void readGraph()
{
int i, x, y;
double w;
memset(cap, 0, sizeof(cap));
scanf("%d %d %d", &n,
&m, &L);
start = 0, end = n+m+1, M = end+1;
for(i = 1; i <= n; ++i)
{
scanf("%lf",
&w);
cap[start][i] = log(w);
cap[i][start] = 0;
}
for(i = 1; i <= m; ++i)
{
scanf("%lf",
&w);
cap[i+n][end] = log(w);
cap[end][i+n] = 0;
}
for(i = 1; i <= L; ++i)
{
scanf("%d %d",
&x, &y);
cap[x][y+n] = INF;
cap[y+n][x] = 0;
}
}
double KM(int start, int end)
{
double result = 0;
memset(flow, 0, sizeof(flow));
queue qu;
while( true )
{
memset(p, -1, sizeof(p));
memset(a, 0, sizeof(a));
a[start] = INF;
qu.push(start);
while( !qu.empty() )
{
int u =
qu.front();
qu.pop();
for(int v =
0; v < M; ++v)
{
if(
!a[v] && cap[u][v] >
flow[u][v])
{
p[v]
= u;
qu.push(v);
a[v]
= min(a[u], cap[u][v]-flow[u][v]);
}
}
}
if(a[end] == 0) break;
for(int u = end; u != start; u
= p[u])
{
flow[p[u]][u]
+= a[end];
flow[u][p[u]]
-= a[end];
}
result += a[end];
}
return result;
}
int main()
{
// freopen("input.txt", "r", stdin);
int caseNum;
scanf("%d", &caseNum);
while(caseNum--)
{
readGraph();
double result = exp(KM(start,
end));
printf("%.4lf\n",
result);
}
return 0;
}
Description
It is year 2500 A.D. and there is a terrible war between the
forces of the Earth and the Mars. Recently, the commanders of the
Earth are informed by their spies that the invaders of Mars want to
land some paratroopers in the m × n grid yard of one
their main weapon factories in order to destroy it. In addition,
the spies informed them the row and column of the places in the
yard in which each paratrooper will land. Since the paratroopers
are very strong and well-organized, even one of them, if survived,
can complete the mission and destroy the whole factory. As a
result, the defense force of the Earth must kill all of them
simultaneously after their landing.
In order to accomplish this task, the defense force wants to
utilize some of their most hi-tech laser guns. They can install a
gun on a row (resp. column) and by firing this gun all paratroopers
landed in this row (resp. column) will die. The cost of installing
a gun in the ith row (resp. column) of the grid yard is
ri (resp. ci ) and the total
cost of constructing a system firing all guns simultaneously is
equal to the product of their costs. Now, your team as a high rank
defense group must select the guns that can kill all paratroopers
and yield minimum total cost of constructing the firing system.
Input
Input begins with a number T showing the number of test
cases and then, T test cases follow. Each test case begins
with a line containing three integers 1 ≤ m ≤ 50 , 1 ≤
n ≤ 50 and 1 ≤ l ≤ 500 showing the number of rows and
columns of the yard and the number of paratroopers respectively.
After that, a line with m positive real numbers greater or
equal to 1.0 comes where the ith number is
ri and then, a line with n positive real
numbers greater or equal to 1.0 comes where the ith number
is ci. Finally, l lines come each
containing the row and column of a paratrooper.
Output
For each test case, your program must output the minimum total
cost of constructing the firing system rounded to four digits after
the fraction point.
Sample Input
1
4 4 5
2.0 7.0 5.0 2.0
1.5 2.0 2.0 8.0
1 1
2 2
3 3
4 4
1 4
Sample Output
16.0000
题意: 地球和火星发生战争, 火星派特工来偷袭地球的武器, 因为火星特工很厉害, 只要一个
生存下来就可以破坏全部. 现在要消灭全部特工, 有消息获得每个特工的降落位置(x,y);
地球用激光枪消灭, 每建造一个可以消灭整行或整列, 但是每行每列的造价不一样, 要求
用最少费用消灭全部敌人. 造价是全部激光枪的费用的乘积.(这里怪怪: product).
解题思路:
1.
题目其实不难, 仔细分析问题: 尽可能用最小费用, 消灭最多的敌人. 每次行列交叉,
都有2个选择. 就像选择路径一样, 但是路径上的敌人会随着你的选择而改变. 图论
中网络流问题. 路径上有容量 和 流量.
2. 果断建图:
设超级源点start = 0, 每行1~n节点X集合, 每列n+1~n+m节点Y集合.
超级汇点end = n+m+1;
从start到X集合的权值(每行费用)表示容量, X集合到Y集容量为INF(无限大), Y集合
到end的权值(每列的费用)表示容量. 样例建图如下图 :
![](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
因为结果要求乘积, 费用就用以10为底的对数表示方便加法, 最后exp转换回来即可.
3.
剩下就是求出网络流-最大流, 每条路径最用最小费用限制了, 这样结果最大流就是
消灭全部敌人最小费用. KM算法(增广路算法)即可.
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define MAX 1005
const int INF = (1<<29);
int n, m, L, p[MAX];
double cap[MAX][MAX], flow[MAX][MAX], a[MAX];
int start, end, M;
inline double min(double a, double b)
{
return a < b ? a : b;
}
void readGraph()
{
int i, x, y;
double w;
memset(cap, 0, sizeof(cap));
scanf("%d %d %d", &n,
&m, &L);
start = 0, end = n+m+1, M = end+1;
for(i = 1; i <= n; ++i)
{
scanf("%lf",
&w);
cap[start][i] = log(w);
cap[i][start] = 0;
}
for(i = 1; i <= m; ++i)
{
scanf("%lf",
&w);
cap[i+n][end] = log(w);
cap[end][i+n] = 0;
}
for(i = 1; i <= L; ++i)
{
scanf("%d %d",
&x, &y);
cap[x][y+n] = INF;
cap[y+n][x] = 0;
}
}
double KM(int start, int end)
{
double result = 0;
memset(flow, 0, sizeof(flow));
queue qu;
while( true )
{
memset(p, -1, sizeof(p));
memset(a, 0, sizeof(a));
a[start] = INF;
qu.push(start);
while( !qu.empty() )
{
int u =
qu.front();
qu.pop();
for(int v =
0; v < M; ++v)
{
if(
!a[v] && cap[u][v] >
flow[u][v])
{
p[v]
= u;
qu.push(v);
a[v]
= min(a[u], cap[u][v]-flow[u][v]);
}
}
}
if(a[end] == 0) break;
for(int u = end; u != start; u
= p[u])
{
flow[p[u]][u]
+= a[end];
flow[u][p[u]]
-= a[end];
}
result += a[end];
}
return result;
}
int main()
{
// freopen("input.txt", "r", stdin);
int caseNum;
scanf("%d", &caseNum);
while(caseNum--)
{
readGraph();
double result = exp(KM(start,
end));
printf("%.4lf\n",
result);
}
return 0;
}
相关文章推荐
- Android的自定义控件起步
- ACM: 图论题 poj 3177 同 3352
- dos批处理中%~dp0%的说明
- ACM: 图论题 poj 2186 强连通分量
- ACM: 博弈题 poj 1143 状态压缩
- 本周学习的代码(数构 深度 广度 优先遍历)
- [原创]关于设置linux中vim 显示行号
- ACM: 动态规划题 poj&nb…
- ACM: 图论题 poj 3…
- 兴趣学习: opencv 实现画图程序
- 兴趣学习: opencv -- 视频读写, 鼠…
- ACM: 动态规划题 poj 2923
- ACM: 动态规划题 poj&nb…
- ACM: 动态规划题 poj 3093 0-1背包
- ACM: 动态规划题 poj&nb…
- ipvsadm-2 DR模式及自动检测后端服务器状态
- ACM: 动态规划题 poj 3211 背包变…
- ACM: 动态规划题 poj&nb…
- ACM: 动态规划题 poj 3659
- ACM: 动态规划题 poj 1192 树形DP