【UVA11419 训练指南】我是SAM 【二分图最小覆盖,最小割】
题意
给出一个R*C大小的网格,网格上面放了一些目标。可以在网格外发射子弹,子弹会沿着垂直或者水平方向飞行,并且打掉飞行路径上的所有目标。你的任务是计算最少需要多少子弹,各从哪些位置发射,才能把所有目标全部打掉。
分析
啊!原来这个模型叫 最小覆盖模型啊!难道不是最小割直接做嘛??
二分图最小覆盖:既选择尽量少的点,使得每条边至少有一个端点被选中。可以证明,最小覆盖数等于最大匹配数。
本题的建模方法:
将每一行看作一个X结点,每一列看作一个Y结点,每个目标对应一条边。这样,子弹打掉左右的目标意味着每条边至少有一个节点被选中。
好吧,我还是说一下我最小割的理解吧。建模一开始还是一样的,每一行为X结点,每一列为Y结点,每个目标对应一条从X到Y的一条边。然后从s向每个X结点连一条容量为1的边。然后每个Y结点都向t结点连一条容量为1的边。求最小割的时候一定是个割从s连出的边或者连向t的边。而如果割s->u这条边,那么就代表这一行打子弹,割v->t也同理。
如果只是输出这个最小的子弹数,那么到这里就结束了,是个非常简单的最小割。但是这个题要输出方案!
按照最小割来说的话,我们要知道,我们割的是哪一条边。一开始我想当然以为就是输出满流的边,但是很显然不对啊!
然后,然后,然后我就去可耻的百度了。
哪些边是最小割的边呢?我们知道,跑完最小割是以后是把所有的点都分为X阵营和Y阵营。那么连接着两个阵营的边就是最小割的边。那么我们只要找出哪些点是X哪些点是Y就可以了。怎么找呢?我们跑完dinic以后,是得到了一个不存在增广路的残量网络的。此时X和Y是分开的,那么只要从s结点开始顺着残量网络的边(包括反向边)跑一个DFS,只要能跑到的点都是X阵营。
具体看下面的代码吧~
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue> using namespace std;
const int maxn=+;
const int INF=; struct Dinic{
int head[maxn],Next[*maxn],to[*maxn],cap[*maxn],flow[*maxn];
int sz,n,m,s,t;
bool vis[maxn];
int cur[maxn],d[maxn];
void init(int n){
this->n=n;
memset(head,-,sizeof(head));
this->sz=-;
}
void add_edge(int a,int b,int c){
++sz;
to[sz]=b;
cap[sz]=c;flow[sz]=;
Next[sz]=head[a];head[a]=sz;
++sz;
to[sz]=a;
cap[sz]=c;flow[sz]=c;
Next[sz]=head[b];head[b]=sz;
}
bool BFS(){
memset(vis,,sizeof(vis));
queue<int>Q;
vis[s]=;
d[s]=;
Q.push(s);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=head[u];i!=-;i=Next[i]){
int v=to[i];
if(!vis[v]&&cap[i]>flow[i]){
vis[v]=;
d[v]=d[u]+;
Q.push(v);
}
}
}
return vis[t];
}
int DFS(int x,int a){
if(x==t||a==)return a;
int Flow=,f;
for(int& i=cur[x];i!=-;i=Next[i]){
int v=to[i];
if(d[v]==d[x]+&&(f=DFS(v,min(a,cap[i]-flow[i])))>){
Flow+=f;
flow[i]+=f;
flow[i^]-=f;
a-=f;
if(a==)break;
}
}
return Flow;
}
int Maxflow(int s,int t){
this->s=s,this->t=t;
int Flow=;
while(BFS()){
for(int i=;i<=n;i++)
cur[i]=head[i]; Flow+=DFS(s,INF);
}
return Flow;
}
}dinic;
int R,C,N;
int foot[maxn];
void get_ans(int u){
foot[u]=;
for(int i=dinic.head[u];i!=-;i=dinic.Next[i]){
int v=dinic.to[i];
if(!foot[v]&&dinic.cap[i]>dinic.flow[i])
get_ans(v);
}
return;
} int main(){
while(scanf("%d%d%d",&R,&C,&N)!=EOF&&(R||C||N)){
memset(foot,,sizeof(foot));
dinic.init(R+C+);
int r,c;
for(int i=;i<=N;i++){
scanf("%d%d",&r,&c);
dinic.add_edge(r,c+R,);
}
for(int i=;i<=R;i++)
dinic.add_edge(,i,);
for(int i=;i<=C;i++)
dinic.add_edge(i+R,C+R+,);
int ans=dinic.Maxflow(,C+R+);
printf("%d ",ans);
get_ans();
for(int i=;i<=R;i++){
if(!foot[i]){
printf("r%d ",i);
}
}
for(int i=;i<=C;i++){
int u=i+R;
if(foot[u]){
printf("c%d ",i);
}
}
printf("\n");
}
return ;
}
【UVA11419 训练指南】我是SAM 【二分图最小覆盖,最小割】的更多相关文章
- 训练指南 UVALive - 3126(DAG最小路径覆盖)
layout: post title: 训练指南 UVALive - 3126(DAG最小路径覆盖) author: "luowentaoaa" catalog: true mat ...
- 二分图&网络流&最小割等问题的总结
二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...
- 【LA3126 训练指南】出租车 【DAG最小路径覆盖】
题意 你在一座城市里负责一个大型活动的接待工作.明天将有m位客人从城市的不同的位置出发,到达他们各自的目的地.已知每个人的出发时间,出发地点和目的地.你的任务是用尽量少的出租车送他们,使得每次出租车接 ...
- [BZOJ]2132: 圈地计划 最小割
圈地计划 Description 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地.据了解,这块土地是一 ...
- 训练指南 UVA - 11419(二分图最小覆盖数)
layout: post title: 训练指南 UVA - 11419(二分图最小覆盖数) author: "luowentaoaa" catalog: true mathjax ...
- 【LA3415 训练指南】保守的老师 【二分图最大独立集,最小割】
题意 Frank是一个思想有些保守的高中老师.有一次,他需要带一些学生出去旅行,但又怕其中一些学生在旅行中萌生爱意.为了降低这种事情发生的概率,他决定确保带出去的任意两个学生至少要满足下面四条中的一条 ...
- 训练指南 UVALive - 4043(二分图匹配 + KM算法)
layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true ...
- 训练指南 UVALive - 3523 (双联通分量 + 二分图染色)
layout: post title: 训练指南 UVALive - 3523 (双联通分量 + 二分图染色) author: "luowentaoaa" catalog: tru ...
- 二分图最小覆盖的Konig定理及其证明,最小的覆盖证明
[转http://www.cppblog.com/abilitytao/archive/2009/09/02/95147.html -> http://yejingx.ycool.com/p ...
随机推荐
- 看了redis想一下
redis总结 要想在python中使用redis,要先在本地安装redis,并开启redis-server,然后再导入python的redis包,pip install redis 怎么在Linux ...
- Google Chrome 调试JS简单教程[更新]
题外话,刚开始我写这篇内容只是将自己了解的一些知识放上来,不巧的是我分析了我的来访日志,很多朋友都有这个需求,为了大家没有白来,我决定充实下这篇文章.最近更新时间2014-02-14 chrome版本 ...
- np.random的随机数函数
np.random的随机数函数(1) 函数 说明 rand(d0,d1,..,dn) 根据d0‐dn创建随机数数组,浮点数, [0,1),均匀分布 randn(d0,d1,..,dn) 根据d0‐dn ...
- 使用Maven运行Solr(翻译)
Solr是一个使用开源的搜索服务器,它采用Lucene Core的索引和搜索功能构建,它可以用于几乎所有的编程语言实现可扩展的搜索引擎. Solr的虽然有很多优点,建立开发环境是不是其中之一.此博客条 ...
- 【转载】Leaflet 中文api
L.Map API各种类中的核心部分,用来在页面中创建地图并操纵地图. 使用 example // initialize the map on the "map" div with ...
- java多线程(1) 线程的基本概念
一.线程的基本概念: 线程是一个程序里面不同的执行路径. 程序里面不同的执行路径,每一个分支都是一个线程. 进程:静态的概念.机器上的一个class文件,机器上的一个exe文件,这叫一个进程. 机 ...
- postman 查看请求,已各种语言方式展示:
查看请求,已各种语言方式展示:
- Windows2012使用笔记
一.介绍 win 2012的名字于北京时间2012年4月18日公布,全称Windows Server 2012(下面简称win 2012),正式版于2012年9月4日发布.这是一套基于Windows ...
- 启动 Eclipse 报错 “An internal error occurred during: "Initializing Java Tooling". java.lang.NullPointerException”
之前在线升级了Eclipse,由于网络/或者是设置问题,在升级完成后启动Eclipse出线上述错误... 解决方法 1. 删除目录工作目录下面的.project文件夹: 如下图: 2. 关闭Eclip ...
- http的含义
HTTP是超文本传输协议,是客户端浏览器或其他程序与Web服务器之间的应用层通信协议.在Internet上的Web服务器上存放的都是 超文本信息,客户机需要通过HTTP协议传输所要访问的超文本信息.H ...