题意:有一个n*m的矩阵,告诉了在每一行或者每一列安装大炮的代价,每一个大炮可以瞬间消灭这一行或者这一列的所有敌人,然后告诉了敌人可能出现的L个坐标位置,问如何安置大炮,使花费最小。如果一个敌人位于第r行c列,则他可以被第r行或者第c列的大炮消灭。
链接:http://poj.org/problem?id=3308
这题突然就让我想起来那个多校的那道多米诺骨牌的那个,几乎一样的模型,还不过要把权值改一下,因为权值是相乘,那么就吧权值改成相加,也就是用log去改变。
这样的话 如果坐标为x,y的点要被消灭,那么要么走x要么走y,这样的话就直接是一个二分图的形式了。一边是行,一边是列,用出现的点连边,就是最小点权模型,最小点权模型就是集合x点的点权做为s-x的边权(流量),y点的权值为y-t的边权,x-y的边权为无穷大,这样见图那么就可以用最大流搞。
这是我曾经看过的一个大神对于二分图边权覆盖的讲解。好像就是这道题。
求二分图顶点覆盖问题,都是转化为最小割问题去求解,转化方法如下:
建超级源S 和超级汇 T,假设二分图两个点集分别为 X 和 Y。X和Y原来的边容量设为INF,将S到X里每个点x连一条边,边权为x的点权,也可以看做覆盖点x的所有出边的花费(W-),将Y里每个点y到T连一条边,边权为y的点权,也可以看做覆盖点y的所有入边的花费(W+)。这样求得最小割容量,即为原问题的解。
/************这是对这个转化方法的解释和证明,有兴趣的同学可以看看************/
X到Y的边权为INF,自然不会成为最小割中的边,那就只有可能是S到X和Y到T中的边,而:S到X中点x的边e1, 权为点x的点权,点x和Y中的所有临边e2,都需要受到e1的流量的限制,同样,X到Y中点y的所有边也会受到点y到T的容量限制。这样求得割就能保证覆盖掉所有的边。
我们可以用反证法证明一下:假设有边<x, y>没有被覆盖掉,则边<S, x>流量为0且边<y, T>流量为0,而<x, y>流量为INF,自然可以找到一条S到T的增流路径<S, x, y, T>,与以求得流为最大流相矛盾,则可以说明,在最大流的情况下,所有的边都已经被覆盖掉。
而最小割问题可以用最大流来解决,问题就变得简单了。
/****************************************************************************/
#include <stdio.h>
#include <iostream>
#include <queue>
#include <string.h>
#include <vector>
#include <cmath>
using namespace std;
const double maxn = 1000000.0;
int m,n,l;
double row[],col[];
struct edge
{
int u,v;
double cap,flow;
};
vector<edge>edges;
vector<edge>ed;
vector<int>g[],G[]; void addedge(int u,int v,double cap,double flow)
{
edges.push_back((edge){u,v,cap,flow});
edges.push_back((edge){v,u,,});
int m;
m = edges.size();
g[u].push_back(m-);
g[v].push_back(m-);
} void init(int n)
{
int i;
for(i = ;i <= n;i++)
{
g[i].clear();
}
edges.clear();
}
int vis[],dis[],cur[];
int bfs(int s,int t,int n)
{
memset(vis,,sizeof(vis));
queue<int>q;
q.push(s);
dis[s] = ;
vis[s] = ; while(!q.empty())
{
int u,v;
u = q.front();
q.pop();
for(int i = ;i < g[u].size();i++)
{
edge &e = edges[g[u][i]];
v = e.v;
if(!vis[v] && e.cap-e.flow > )
{
vis[v] = ;
dis[v] = dis[u] +;
q.push(v);
}
}
}
return vis[t];
}
double dfs(int u,double a,int t)
{
if(u == t || a == )
return a;
int v;
double flow = ,f;
for(int& i = cur[u]; i < g[u].size();i++)
{
edge &e = edges[g[u][i]];
v = e.v;
if(dis[u]+ == dis[v] &&(f = dfs(v,min(a,e.cap-e.flow),t)))
{
e.flow += f;
edges[g[u][i]^].flow -= f;
flow += f;
a -= f;
if(a == )
break;
}
} return flow;
}
double maxflow(int s,int t)
{
double flow = ;
while(bfs(s,t,t))
{
memset(cur,,sizeof(cur));
flow+=dfs(s,,t);
}
return flow;
} int main()
{
int i,j;
int t; while(~scanf("%d",&t))
{
while(t--)
{
scanf("%d %d %d",&n,&m,&l);
init(n+m+); for(i=;i <= n;i++)
scanf("%lf",&row[i]); for(i = ;i <= m;i++)
scanf("%lf",&col[i]); int u,v; for(i = ;i <= n;i++)
addedge(,i,log(row[i]),);
for(i = ;i <= m;i++)
addedge(n+i,n+m+,log(col[i]),); for(i = ;i <= l;i++)
{
int a,b;
scanf("%d %d",&a,&b);
addedge(a,n+b,maxn,);
} double ans = maxflow(,n+m+);
printf("%.4f\n",exp(ans));
}
} return ;
}
poj3308 Paratroopers 最大流 最小点权覆盖的更多相关文章
-
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 ...
-
POJ3308 Paratroopers(最小割/二分图最小点权覆盖)
把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖. 此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运 ...
-
poj3308 Paratroopers --- 最小点权覆盖-&;gt;最小割
题目是一个非常明显的二分图带权匹配模型, 加入源点到nx建边,ny到汇点建边,(nx.ny)=inf建边.求最小割既得最小点权覆盖. 在本题中因为求的是乘积,所以先所有取log转换为加法,最后再乘方回 ...
-
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(最小点权覆盖)(对数乘转加)
http://poj.org/problem?id=3308 r*c的地图 每一个大炮可以消灭一行一列的敌人 安装消灭第i行的大炮花费是ri 安装消灭第j行的大炮花费是ci 已知敌人坐标,同时消灭所有 ...
-
POJ - 3308 Paratroopers (最小点权覆盖)
题意:N*M个格点,K个位置会有敌人.每行每列都有一门炮,能打掉这一行(列)上所有的敌人.每门炮都有其使用价值.总花费是所有使用炮的权值的乘积.求最小的总花费. 若每门炮的权值都是1,就是求最小点覆盖 ...
-
hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)
/** 转自:http://blog.csdn.net/u011498819/article/details/20772147 题目:hdu1569 方格取数(2) 链接:https://vjudge ...
-
POJ 2125 Destroying the Graph 二分图最小点权覆盖
Destroying The Graph Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8198 Accepted: 2 ...
随机推荐
-
Node.js入门笔记(6):web开发方法
使用node进行web开发 用户上网流程: 表面上看:打开浏览器--输入网址--跳转--上网. 背后的过程是什么呢? http请求网址到指定的主机--服务器接收请求--服务器响应内容到用户浏览器--浏 ...
-
Linux学习笔记(16)shell基础之Bash变量
1. 用户自定义变量 (1)变量设置规则 ① 变量名称可由字母.数字和下划线组成,但不能以数字开头: ② 变量的默认类型为字符串类型,如果要对数值运算,则必须指定变量类型为数值型: ③ 变量用等号连接 ...
-
异步请求---Get
前端 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> &l ...
-
BeautifulSoup库children(),descendants()方法的使用
BeautifulSoup库children(),descendants()方法的使用 示例网站:http://www.pythonscraping.com/pages/page3.html 网站内容 ...
-
Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks 阅读笔记
Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks (使用循环一致的对抗网络的非配对图像-图 ...
-
Ubuntu系统安装Transmission
虚拟机Ubuntu 16.10 Transmission 2.92(https://launchpad.net/~transmissionbt/+archive/ubuntu/ppa) 一.添加源 s ...
-
loadrunner 上传下载
转http://blog.163.com/yings_9371/blog/static/66196922010711115545137/ (1)LoadRunner上传文件 web_submit_da ...
-
Linux下完全删除用户
实验环境:Centos7虚拟机 首先创建一个普通用户gubeiqing. [root@localhost ~]# useradd gubeiqing [root@localhost ~]# passw ...
-
Android 记录点滴
1:关于断点 设置断点点三角是进不去的,这个是类似c#的release 正式版, 点第二个红圈内的debug的那个按钮才可以 . 这个按钮可以让程序及时进入当前断点处 2:对于背景颜色 andro ...
-
工作->;离职->;考研
1.工作篇 去年我大三,理论上来说我应该考研,也必须考研,我当时的想法也是这样.但是不知道什么情况,我竟然选择了工作,连我也没想到的反转,可能当时我对自己的技术很自信?我想可能是,有点对自己技术觉得还 ...