题意

给出一个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 【二分图最小覆盖,最小割】的更多相关文章

  1. 训练指南 UVALive - 3126(DAG最小路径覆盖)

    layout: post title: 训练指南 UVALive - 3126(DAG最小路径覆盖) author: "luowentaoaa" catalog: true mat ...

  2. 二分图&网络流&最小割等问题的总结

    二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...

  3. 【LA3126 训练指南】出租车 【DAG最小路径覆盖】

    题意 你在一座城市里负责一个大型活动的接待工作.明天将有m位客人从城市的不同的位置出发,到达他们各自的目的地.已知每个人的出发时间,出发地点和目的地.你的任务是用尽量少的出租车送他们,使得每次出租车接 ...

  4. [BZOJ]2132: 圈地计划 最小割

    圈地计划 Description 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地.据了解,这块土地是一 ...

  5. 训练指南 UVA - 11419(二分图最小覆盖数)

    layout: post title: 训练指南 UVA - 11419(二分图最小覆盖数) author: "luowentaoaa" catalog: true mathjax ...

  6. 【LA3415 训练指南】保守的老师 【二分图最大独立集,最小割】

    题意 Frank是一个思想有些保守的高中老师.有一次,他需要带一些学生出去旅行,但又怕其中一些学生在旅行中萌生爱意.为了降低这种事情发生的概率,他决定确保带出去的任意两个学生至少要满足下面四条中的一条 ...

  7. 训练指南 UVALive - 4043(二分图匹配 + KM算法)

    layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true ...

  8. 训练指南 UVALive - 3523 (双联通分量 + 二分图染色)

    layout: post title: 训练指南 UVALive - 3523 (双联通分量 + 二分图染色) author: "luowentaoaa" catalog: tru ...

  9. 二分图最小覆盖的Konig定理及其证明,最小的覆盖证明

    [转http://www.cppblog.com/abilitytao/archive/2009/09/02/95147.html  ->  http://yejingx.ycool.com/p ...

随机推荐

  1. smarty 模板编译和变量调节器 模板引入

    <?php require './smarty/Smarty.class.php'; $sm = new Smarty; //$sm->force_compile = true; $sm- ...

  2. GOF23设计模式之访问者模式(visitor)

    一.访问者模式概述 (1)模式动机   对于存储在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口),对于该集合中的对象,可以接受一类称为访问者的对象来访问,不同的访问者其访问方式也有所 ...

  3. GOF23设计模式之观察者模式(observer)

    一.观察者模式概述 观察者模式主要用于 1 :N 的通知.当一个对象(目标对象 Subject 或 Observable)的状态变化时,它需要通知一系列对象(观察者对象 Observer),令它们做出 ...

  4. GOF23设计模式之享元模式(flyweight)

    一.享元模式概述 内存属于稀缺资源,不要随便浪费.如果有很多个完全相同或相似的对象,可以通过享元模式,节省内存. 享元模式核心: (1)享元模式可以共享的.方式高效的支持大量细粒度对象的重用: (2) ...

  5. Big Water Problem

    链接:https://www.nowcoder.com/acm/contest/77/B来源:牛客网 Big Water Problem 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ ...

  6. 十六 在沉睡中停止(在sleep() 状态下停止线程)

    1 如果线程在sleep()状态下停止线程,会是什么效果? 答案: 如果在sleep状态下停止某一线程,会进入sleep的catch块中, 抛出InterruptedException 异常,并且清除 ...

  7. Cookie与Session的复习

    Cookie Cookie是HTTP协议制定的.先由服务器保存Cookie到浏览器,再下次浏览器请求服务器时把上一次请求得到Cookie再归还给服务器.由服务器创建保存到客户端浏览器的一个键值对(由服 ...

  8. 显示本月日历demo

    import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.GregorianCalendar; p ...

  9. sqlserver并发处理,锁和事务

      本文系转载,谢谢:http://www.cnblogs.com/cxd4321/archive/2008/12/10/1351792.html     另外这个也不错 http://www.cnb ...

  10. Django的路由层(URLconf)

    URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对 ...