poj3308
二分图的最小点权覆盖,选定点集,与该点集有关的边覆盖所有顶点,且该点集的点权值和最小。
有类似于匈牙利算法一样的带权匹配算法,但是这里就不介绍了。个人比较推荐,用最大流算法更好理解,写起来更容易。
题意:一个m X n的方阵,方阵格子中有老鼠屎,神枪手一枪能打掉一行或者一列上的所有赃物,让选定某些行和某些列,打掉所有赃物。已知条件: m、n,老鼠屎l粒,在每一行和列上布置神枪手的花费ci、cj,l粒老鼠屎的坐标。总费用为选定的行和列对应的花费值乘积,求最小总费用。
第一步:化积为和,使用幂函数,最后得到结果时再还原!!!
第二步:最大流算法求最小点权覆盖。
先弱弱证明一下该算法。坐标为(i,j)的老鼠屎,第i行和第j列必选之一,点覆盖必选边两个端点之一。假设仅有某一行i上,第a、b、c(可以更多)列上有老鼠屎,选定i行或者选定对应的所有列,也即两者之一必有一个是在最小割中。
- 若(条件1)Α第i行的费用小于所有列,选行i,否则(条件2)选列。
- 若再有某一行ii(ii != i)有a、b、d、e列上有老鼠屎,若上一步(条件1)为真,ii行的费用减去第i行中行与列的差(此差值也进入最小割,当然有可能行ii的费用更小,那样就是ii的费用进入最小割了)否则,对于此行a、b就不考虑,行ii与 d、e列像上一步一样考虑。
- 把i行和ii行看成一行,继续对后面的行进行第二步判定。
此最小点权覆盖就和最小割联系起来了。
只是个博客,写的不是特别学术,希望读者能看懂。
贴个代码,祝好运!
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
#define maxn 500
const int maxe = ;
const double maxf = 1e10;
#define zero 1e-8
struct edge{
int u,v; double c;
edge(int e1=,int e2=,double e3=){ u=e1,v=e2; c=e3; }
}e[maxe];
int ec;
int head[maxn];
int next[maxe];
void addedge(int u,int v,double c){
e[ec]=edge(u,v,c);
next[ec]=head[u]; head[u]=ec++;
//printf("%d --> %d , c = %.5f\n",u,v,c);
e[ec]=edge(v,u,);
next[ec]=head[v]; head[v]=ec++;
}
//***********************************//
int source,sink,maxdep;
int dep[maxn],gap[maxn];
void setGD(){
for(int i=;i<=maxdep;i++) dep[i] = maxdep; dep[sink] = ;
int u,v;
queue<int> que;
que.push(sink);
while(!que.empty()){
u = que.front(); que.pop();
for(int i=head[u];i!=-;i=next[i]){
v = e[i].v; //if(v > maxdep) continue;
if(dep[v] < maxdep) continue; //'被访问过'
dep[v] = dep[u]+;
que.push(v);
}
}
memset(gap,,sizeof(gap));
for(int i=;i<=maxdep;i++) gap[dep[i]]++;
}
double maxF(){
setGD();
int u=source,i;
int cur[maxn],trace[maxn],top=;
for(int i=;i<=maxdep;i++) cur[i] = head[i];
double flow=;
while(dep[source] <= maxdep){
if(u == sink){
double tf = maxf; int ins;
for(i=;i<top;i++) //找瓶颈边
if(tf - e[trace[i]].c > )
tf = e[trace[i]].c, ins = i;
for(i=;i<top;i++){
e[trace[i]].c -= tf;
e[trace[i]^].c += tf;
}
flow += tf;
u = e[trace[ins]].u, top = ins;
}
if(u != sink && gap[dep[u]-]==) break;
for(i=cur[u];i!=-;i=next[i])
if(e[i].c > zero && dep[u] == dep[e[i].v] + )
break;
if(i != -) {
trace[top++] = i;
cur[u] = i;
u = e[i].v;
}
else {
int mindep = maxdep;
for(i=head[u];i!=-;i=next[i]){
if(e[i].c > zero && dep[e[i].v] < mindep)
mindep = dep[e[i].v], cur[u] = i;
}
gap[dep[u]]--;
dep[u] = mindep + ;
gap[dep[u]]++;
if(u != source)
u = e[trace[--top]].u;
}
}
return flow;
}
//**********************************//
void initial(){
ec = ;
memset(head,-,sizeof(head));
//initial source ,sink and maxdep;
}
int main()
{
int cases; cin>>cases;
int n,m,l;
for(int cas=;cas<cases;cas++){
initial();
scanf("%d%d%d",&m,&n,&l);
source=;
sink=n+m+; maxdep=sink+;
double tt;
for(int i=;i<=m;i++)
scanf("%lf",&tt), addedge(source,i,log10(tt));
for(int i=;i<=n;i++)
scanf("%lf",&tt), addedge(i+m,sink,log10(tt));
int u,v;
for(int i=;i<=l;i++){
scanf("%d%d",&u,&v);
addedge(u,v+m,maxf);
}
double ret = maxF();
printf("%.4f\n",pow(,ret));
}
return ;
}
poj3308的更多相关文章
- ACM/ICPC 之 伞兵-最小割转最大流(POJ3308)
//以行列建点,伞兵位置为单向边-利用对数将乘积转加法 //最小割转最大流 //Time:63Ms Memory:792K #include<iostream> #include<c ...
- POJ3308 Paratroopers(最小割/二分图最小点权覆盖)
把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖. 此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运 ...
- POJ3308 Paratroopers(网络流)(最小割)
Paratroopers Time Limit: 1000MS Memory Limit: 655 ...
- poj3308 Paratroopers --- 最小点权覆盖->最小割
题目是一个非常明显的二分图带权匹配模型, 加入源点到nx建边,ny到汇点建边,(nx.ny)=inf建边.求最小割既得最小点权覆盖. 在本题中因为求的是乘积,所以先所有取log转换为加法,最后再乘方回 ...
- poj3308 Paratroopers 最大流 最小点权覆盖
题意:有一个n*m的矩阵,告诉了在每一行或者每一列安装大炮的代价,每一个大炮可以瞬间消灭这一行或者这一列的所有敌人,然后告诉了敌人可能出现的L个坐标位置,问如何安置大炮,使花费最小.如果一个敌人位于第 ...
- poj3308 Paratroopers
Description It is year 2500 A.D. and there is a terrible war between the forces of the Earth and the ...
- poj3308 最小割
因为行可以了,那列就不行,所以根据行列建立最小割模型. 然后这题精妙之处在于把乘法取对数后转化为加法,瞬间就简单了. 保证精度,C++AC ,16MS G++WA. #include<stdio ...
- poj3308 最小点权覆盖
Paratroopers Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8837 Accepted: 2663 Desc ...
- poj分类 很好很有层次感。
初期: 一.基本算法: (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586) (3)递归和分治法. ( ...
随机推荐
- Jackson 框架,轻易转换JSON【转】
Jackson 框架,轻易转换JSON Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 前面有介绍过json-lib这个框架,在 ...
- 排颜色问题——数组 leetcode lintcode
问题描写叙述: 给一个数组,而且数组里面元素的值仅仅可能是0,1,2,然后如今把这个数组排序. 第二种表述: 现有n个红白蓝三种不同颜色的小球,乱序排列在一起,请通过两两交换随意两个球,使得从左至右, ...
- 理解数据点,自变量和因变量(参数和值)ChartControl
WinForms Controls > Controls > Chart Control > Fundamentals > Charting Basics > Under ...
- 关于用exec来执行存储过程中,参数带有引号的解决方法
比如:exec 存储过程名 要带有引号的参数 这样写的时候是传不进引号的,可以选定一种字符来表示引号,在存储过程中再进行转换: @test=replace(replace(@test,char(39) ...
- JavaScript的一点简介(注:本文诸多观点源于JavaScript高级程序设计,如有侵权,立即删除)
JavaScript是一门最易让人误解的语言,该语言中精华与糟粕并存(可能比一般语言的这个比例要大一些):但“千淘万漉虽辛苦,吹尽黄沙始到金”,层层面纱下是易用灵活.优雅轻灵的内在.很久以前,Java ...
- C++学习笔录1
1.在实际开发中,引用类型变量值用于函数的参数中.它不会另外开辟空间(提高了程序效率),他相当于变量的别名,代表的就是当前这个变量的地址空间.(引用的底层用的是指针.因此从底层的角度讲,其实它的效率是 ...
- poj1160
题目大意:在一个一维坐标轴上有v个(1<=v<=300)村庄,要建p(1<=p<=30)个邮局,每个村庄都到最近的邮局,要求最小的距离和. 四边形不等式,据说黑书上写得很高 ...
- poco vs Boost[ZZ]
http://wooce.iteye.com/blog/634395 POCO的优点: 1) 比boost更好的线程库,特别是一个活动的方法的实现,并且还可设置线程的优先级. 2) 比 boost:a ...
- phpcms-v9 --- 如何通过{pc}标签获取全站文章内容?
1.phpcms-v9默认情况下只能根据catid获取当前栏目及子栏目下的文章,但是有时候我们需要如何通过{pc}标签来获取全站文章内容的需求,应该怎么做呢? 第一步:在content_tag.cla ...
- jQuery 1.9不支持$.browser 怎么判断浏览器类型和版本
$.browser.mozilla = /firefox/.test(navigator.userAgent.toLowerCase());$.browser.webkit = /webkit/.te ...