POJ - 3308 Paratroopers(最大流)
1、这道题学了个单词,product 还有 乘积 的意思。。
题意就是在一个 m*n的矩阵中,放入L个敌军的伞兵,而我军要在伞兵落地的瞬间将其消灭。现在我军用一种激光枪组建一个防御系统,这种枪可以安装在一行(或者一列),并且安装在不同行(或者不同列)的费用是不一样的,枪的攻击范围是一行(或者一列)。安装所有枪的费用是它们每个费用的“乘积”,现在求组建这个系统需要的最小费用。
2、与前面做的二分图的一道题有点相似(POJ - 3041 Asteroids(最小点覆盖数))。但是现在这道题在不同行(或者不同列)的费用不同,所以还是有区别的。(ps:也就是说,之前那个把费用都设为1,也可以用这道题的方法来做?应该是的。)
建图:与上述的题类似,把行、列分别拆出来,分别作为二分图的X集、Y集中的点即可。然后在所建的二分图上加入超级源点(_S)、超级汇点(_T),再求最大流。
为什么求的最大流保证费用最小呢?因为对应二分图(加入源点、汇点后)中,总是选的_S->u 和v->_T 中的费用小的(即流量小的),并且覆盖了中间所有边(即不加源点、汇点前的二分图中的所有边)(好像是~,未证明)。
这里因为求的是乘积,所以用对数转化下:建图时,流量为 log(cost)即对各个cost求自然对数;再求出最大流maxflow,最后求 e^maxflow。(因为a*b*c=e^(loga+logb+logc);)
下面对题目样例作个解释:可忽略。

图中最大流的那个图里,画圈圈的是这条边满流(自己起的名,例:2/2),也就是有可能选的某行或某列(我是这么理解的),也就是说有可能不选它(例:1.5/1.5)。
下面解释样例为什么不选1.5/1.5而选2/2(即不选第1列而选第1行),因为选第1列的话,必须同时选第4列,才能代替选第1行和第4行,经比较,费用变大,所以不选。
对这种怎么选的情况,举个栗子,如图:

上面的为可替代的情况,
下面的为不可替代的情况。
3、
3、ISAP邻接表形式:直接用的这个速度比较好的模板
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std; const int MAXN=;//点数的最大值
const int MAXM=;//边数的最大值(加的双向加,所以是2倍,别忘了加上超级源点和超级汇点)
const int INF=0x3f3f3f3f;
struct Edge{
int to,next;
double cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
void init(){
tol=;
memset(head,-,sizeof(head));
}
//加边,单向图三个参数,双向图四个参数
void addedge(int u,int v,double w,double rw=){
edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];
edge[tol].flow=;head[u]=tol++;
edge[tol].to=u;edge[tol].cap=rw;edge[tol].next=head[v];
edge[tol].flow=;head[v]=tol++;
}
//输入参数:起点、终点、点的总数
//点的编号没有影响,只要输入点的总数
double sap(int start,int end,int N){
memset(gap,,sizeof(gap));
memset(dep,,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u=start;
pre[u]=-;
gap[]=N;
double ans=;
while(dep[start]<N){
if(u==end){
double Min=INF;
for(int i=pre[u];i!=-;i=pre[edge[i^].to])
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
for(int i=pre[u];i!=-;i=pre[edge[i^].to]){
edge[i].flow+=Min;
edge[i^].flow-=Min;
}
u=start;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-;i=edge[i].next){
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+==dep[u]){
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag){
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-;i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){
Min=dep[edge[i].to];
cur[u]=i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u]=Min+;
gap[dep[u]]++;
if(u!=start)u=edge[pre[u]^].to;
}
return ans;
} int main(){
int T;
int m,n,L;
double ri,ci;
int _S,_T;//超级源点,超级汇点
int r,c; scanf("%d",&T);
while(T--){
init();
scanf("%d%d%d",&m,&n,&L);
_S=m+n;
for(int i=;i<m;++i){
scanf("%lf",&ri);
addedge(_S,i,log(ri));
}
_T=m+n+;
for(int i=;i<n;++i){
scanf("%lf",&ci);
addedge(m+i,_T,log(ci));
} for(int i=;i<L;++i){
scanf("%d%d",&r,&c);
addedge(r-,m+c-,INF);
} printf("%.4f\n",exp(sap(_S,_T,m+n+)));
}
return ;
}
ps:当时因为 product 没读懂题,就搜了一下,搜到了这个博客:POJ 3308 Paratroopers
POJ - 3308 Paratroopers(最大流)的更多相关文章
- POJ 3308 Paratroopers 最大流,乘积化和 难度:2
Paratroopers Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7267 Accepted: 2194 Desc ...
- POJ 3308 Paratroopers(最小割EK(邻接表&矩阵))
Description It is year 2500 A.D. and there is a terrible war between the forces of the Earth and the ...
- POJ 3308 Paratroopers(最小点权覆盖)(对数乘转加)
http://poj.org/problem?id=3308 r*c的地图 每一个大炮可以消灭一行一列的敌人 安装消灭第i行的大炮花费是ri 安装消灭第j行的大炮花费是ci 已知敌人坐标,同时消灭所有 ...
- poj 3308 Paratroopers
http://poj.org/problem?id=3308 #include <cstdio> #include <cstring> #include <algorit ...
- POJ - 3308 Paratroopers (最小点权覆盖)
题意:N*M个格点,K个位置会有敌人.每行每列都有一门炮,能打掉这一行(列)上所有的敌人.每门炮都有其使用价值.总花费是所有使用炮的权值的乘积.求最小的总花费. 若每门炮的权值都是1,就是求最小点覆盖 ...
- POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)
Description It is year 2500 A.D. and there is a terrible war between the forces of the Earth and the ...
- POJ 3308 Paratroopers (对数转换+最小点权覆盖)
题意 敌人侵略r*c的地图.为了消灭敌人,可以在某一行或者某一列安置超级大炮.每一个大炮可以瞬间消灭这一行(或者列)的敌人.安装消灭第i行的大炮消费是ri.安装消灭第j行的大炮消费是ci现在有n个敌人 ...
- poj 3308 Paratroopers(二分图最小点权覆盖)
Paratroopers Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8954 Accepted: 2702 Desc ...
- POJ 3308 Paratroopers(最小割EK)
题目链接 题意 : 有一个n*m的矩阵,L个伞兵可能落在某些点上,这些点的坐标已知,需要在某些位置安上一些枪,然后每个枪可以将一行或者一列的伞兵击毙.把这种枪安装到不同行的行首.或者不同列的列首,费用 ...
随机推荐
- c# 类如何生成dll文件及引用
1.打开“工具”菜单下的“外部工具”子菜单: 2.点击“添加按钮,增加一个菜单,菜单内容填写如下: 注意参数那里为:/k "C:\vs2010\VC\vcvarsall.bat" ...
- 【思维】2017多校训练七 HDU6121 Build a tree
http://acm.hdu.edu.cn/showproblem.php?pid=6121 [题意] 询问n个结点的完全k叉树,所有子树结点个数的异或和是多少 [思路] 一棵完全K叉树,对于树的每一 ...
- SDWebImage实现分析
该博文来自南峰子的技术博客,文章从下载和缓存俩个大的组件分析到里面一些核心方法的实现,条理清晰,相对于一些一上来就通篇分析实现思路的技术文章, 这篇的讲解思路明确,框架架构也讲的比较清楚.看完这篇再去 ...
- [NOIP2000] 提高组 洛谷P1022 计算器的改良
题目背景 NCL是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能.实验室将这个任务交给了一个刚进入的新手ZL先生. ...
- UVA 10245 The Closest Pair Problem【分治】
题目链接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=21269 题意: 求平面最近点对. 分析: 经典问题. n比 ...
- Html.EditorFor 加 htmlAttributes
@Html.EditorFor(m => m.Name, new { htmlAttributes = new { @required = "true", @anotherA ...
- jdk8 stream可以与list,map等数据结构互相转换
前面我们使用过collect(toList()),在流中生成列表.实际开发过程中,List又是我们经常用到的数据结构,但是有时候我们也希望Stream能够转换生成其他的值,比如Map或者set,甚至希 ...
- 你创建线程池最好分为两种线程池,io密集型线程池,或者cpu密集型线程池
你创建线程池最好分为两种线程池,io密集型线程池,或者cpu密集型线程池. 否则,如果只用一个线程池的话,不管是iO密集的线程,或者cpu消耗大的都放在同一个线程池的话,会发生线程池被撑满的情况
- 了解kaggle
Kaggle官网 数据挖掘的比赛,主要是特征工程 Kaggle 数据挖掘比赛经验分享 Kaggle 机器学习竞赛冠军及优胜者的源代码汇总 程序化广告交易中的点击率预估
- Deepin-键盘快捷键
是不是很happy呢? 可以用键盘替代鼠标点点点了! 1.鼠标移到右下角 2.下翻找到"快捷键" 3.自定义一个 4.示例(首先编写个简单的Shell) 程序一般放在/usr/bi ...