网络流/二分图最小点权覆盖


  sigh……这题……TLE&RE了好几发

  建一个二分图,左边的每个结点代表行,右边的代表列,如果在(i,j)这个位置有一个外星人,那么我们就连一条边 (左 i ->右 j),这样的话,求一个二分图最小点权覆盖即可。

  为什么这样建图是对的?大家学过二分图应该知道点覆盖是啥吧……(至少学过最小点覆盖=最大匹配吧?)那么我们选了某一个点,比如我们选了左边的第 i 个点,这就表示我们在第 i 行建了一座激光炮,它能打到的外星人就是这个点连出去的所有边!也就是说对于每个外星人(每条边),它被打死(边被覆盖)当且仅当它所在行或列至少有一个方向有激光炮(它连接的两个端点至少有一个被选中),那么现在应该明白了吧= =我们就是要选出权值和最小的一组点,使得所有边都被覆盖。这个用网络流来做比较方便……(其实是我不会别的做法……)

  那么我们现在知道了这是一个二分图的模型,那么怎么建网络流的图呢?对于每个左边的顶点,我们连s->i,w=r[i],右边顶点连汇点t,边权(流量)同理。然后对于二分图中的边我们连(左->右,流量为INF),跑一个最大流(最小割)。(割掉某条边就表示选这个点,边权为INF表示不割它)

  看到这里你可能会问,这样做是不对的吧?样例都过不了的……

  其实……一开始我由于英语没学好……“product”的意思是乘积!!!也就是所有建造的激光炮的权值之积……sigh

  辣么怎么算积的最大值呢?网络流不是只能算和的最大值吗?下面就是见证奇迹的时刻:对所有的权值取log,然后对最终答案取exp!这样就华丽丽地将求乘积最大转化为了求和最大。

  

Trick:这题是取了log的边权……所以在用Dinic增广的时候边界判定需要小心小心再小心。对于double类型的最大流我参考网上的代码重新写了一个模板……

之前在【当前结点是否无法再继续增广(dfs时)】这个地方蛋疼了好久……因为边界处理的不好各种TLE

然后是边集开小了……500×2的RE,500×3的AC……

 Source Code
Problem: User: sdfzyhy
Memory: 760K Time: 0MS
Language: G++ Result: Accepted Source Code //POJ 3308
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int N=,M=,INF=;
const double eps=1e-;
typedef long long LL;
/******************tamplate*********************/ int n,m,l;
double r[N],c[N];
struct edge{
int from,to;
double cap,flow;
};
struct Net{
edge E[M*];
int head[N],next[M*],cnt;
int Q[N];
int s,t,d[N],cur[N];
inline void add(int from,int to,double cap){
E[++cnt]=(edge){from,to,cap,};
next[cnt]=head[from];
head[from]=cnt;
E[++cnt]=(edge){to,from,,};
next[cnt]=head[to];
head[to]=cnt;
}
inline void init(){
cnt=;
n=getint();m=getint();l=getint();
s=; t=n+m+;
F(i,s,t) head[i]=;
F(i,,n){
scanf("%lf",&r[i]);
add(s,i,log(r[i]));
}
F(i,,m){
scanf("%lf",&c[i]);
add(i+n,t,log(c[i]));
}
int x,y;
F(i,,l){
x=getint(); y=getint();
add(x,y+n,INF);
}
}
bool mklevel(){
memset(d,-,sizeof d);
d[s]=;
int l=,r=-;
Q[++r]=s;
while(l<=r){
int x=Q[l++];
for(int i=head[x];i;i=next[i]){
edge&e=E[i];
if (d[e.to]==- && e.cap>e.flow){
d[e.to]=d[x]+;
Q[++r]=(e.to);
}
}
}
return d[t]!=-;
}
double dfs(int x,double a){
if (x==t) return a;
double flow=;
for(int &i=cur[x];i && flow<a;i=next[i]){
edge&e=E[i];
if (e.cap-e.flow> && d[e.to]==d[x]+){
double f=dfs(e.to,min(a-flow,e.cap-e.flow));
flow+=f;
e.flow+=f;
E[i^].flow-=f;
}
}
if (!flow) d[x]=-;
return flow;
}
double Dinic(){
double flow=;
while(mklevel()){
F(i,s,t) cur[i]=head[i];
flow+=dfs(s,INF);
}
return flow;
}
}G1; int main(){
#ifndef ONLINE_JUDGE
freopen("3308.in","r",stdin);
freopen("3308.out","w",stdout);
#endif
int T=getint();
while(T--){
G1.init();
printf("%.4f\n",exp(G1.Dinic()));
}
return ;
}

【POJ】【3308】Paratroopers的更多相关文章

  1. 【 POJ - 1204 Word Puzzles】(Trie+爆搜|AC自动机)

    Word Puzzles Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 10782 Accepted: 4076 Special ...

  2. 【POJ 1459 power network】

    不可以理解的是,测评站上的0ms是怎么搞出来的. 这一题在建立超级源点和超级汇点后就变得温和可爱了.其实它本身就温和可爱.对比了能够找到的题解: (1)艾德蒙·卡普算法(2)迪尼克算法(3)改进版艾德 ...

  3. 【POJ 2728 Desert King】

    Time Limit: 3000MSMemory Limit: 65536K Total Submissions: 27109Accepted: 7527 Description David the ...

  4. 【POJ 2976 Dropping tests】

    Time Limit: 1000MSMemory Limit: 65536K Total Submissions: 13849Accepted: 4851 Description In a certa ...

  5. 【POJ 3080 Blue Jeans】

    Time Limit: 1000MSMemory Limit: 65536K Total Submissions: 19026Accepted: 8466 Description The Genogr ...

  6. 【POJ各种模板汇总】(写在逆风省选前)(不断更新中)

    1.POJ1258 水水的prim……不过poj上硬是没过,wikioi上的原题却过了 #include<cstring> #include<algorithm> #inclu ...

  7. 【POJ 3669 Meteor Shower】简单BFS

    流星雨撞击地球(平面直角坐标第一象限),问到达安全地带的最少时间. 对于每颗流星雨i,在ti时刻撞击(xi,yi)点,同时导致(xi,yi)和上下左右相邻的点在ti以后的时刻(包括t)不能再经过(被封 ...

  8. 【POJ 2823 Sliding Window】 单调队列

    题目大意:给n个数,一个长度为k(k<n)的闭区间从0滑动到n,求滑动中区间的最大值序列和最小值序列. 最大值和最小值是类似的,在此以最大值为例分析. 数据结构要求:能保存最多k个元素,快速取得 ...

  9. 【POJ 2406 Power Strings】

    Time Limit: 3000MSMemory Limit: 65536K Description Given two strings a and b we define a*b to be the ...

  10. bzoj 2295: 【POJ Challenge】我爱你啊

    2295: [POJ Challenge]我爱你啊 Time Limit: 1 Sec  Memory Limit: 128 MB Description ftiasch是个十分受女生欢迎的同学,所以 ...

随机推荐

  1. 理解C#系列 / .NET体系结构

    .NET体系结构 索引 前提条件 编程 编程语言 编程语言之一:C# C#依赖.NET平台 .NET平台下的公共语言运行库 .NET平台下的基础类库 C#可以开发什么? 前提条件 [最低配置]知道什么 ...

  2. python:笔记for循环中的else

    我们常常会在for循环遍历一个序列或者字典后,接着语句else,很多新手会误以为是判断执行else后面的 代码,其实不然,for循环里面也不存在判断,而已执行完遍历的对象后,再执行else后面的代码. ...

  3. <img>元素底部为何有空白?

    原因: 图片文字等inline元素默认是和父级元素的baseline对齐的,即:vertical-align 的默认值是 baseline:而baseline又和父级底边bottom有一定距离: im ...

  4. Android四大组件之一:Service(服务)

    Service跟Activity也是出于统一级别的组件,且与Activity的最大区别之一主要是没有人机界面,主要是运行在程序的后台(我是这么理解的),帮助文档上说的是运行于进程的主线程中,但是服务并 ...

  5. c++之RTTI介绍

    本文介绍c++的RTTI的基本用法,并初步研究RTTI的实现原理. 1. 什么是RTTI RTTI即运行时类型识别(runtime type identification),用于判断指针或引用所绑定对 ...

  6. java和javascript中this区别的浅探讨

    今天在学习javascript的时候碰到了this,感觉它跟java里的有点不一样.然后上网查了一下,参考了这篇文章,JavaScript中this关键字详解,发现它们之间的区别主要是这样: java ...

  7. C# 玩家昵称屏蔽敏感字眼

    功能:使用正则  对玩家昵称处理,如果含有 屏蔽字库里的敏感字眼进行屏蔽.已封装成dll 1.屏蔽字库处理成所需要的正则格式:(所需正则表达式格式:".*((XX)|(XX)|(XX)|.. ...

  8. mysql mmm高可用架构设计

    项目概述:搭建主从,双主,安装Perl模块  安装配置mmm软件  测试 硬件环境:4台虚拟PC 软件环境:rehl6.5 MySQL-5.6.26 percona-xtrabackup-2.3.4 ...

  9. 2015.1写留言板的时用的 知识点和函数 --->总结

    一:时间函数和uniqid() 1:uniqid():生成唯一的id, 无参数返回的字符串的长度为13,有参数为23 2:时间和时间戳相互转换的php函数 ①:time()  返回当前unix的时间戳 ...

  10. Node.js学习资料整理

    了解node,node主要能干啥? Node.js究竟是什么?:http://www.ibm.com/developerworks/cn/opensource/os-nodejs/ nodejs教程: ...