【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阵营。

 具体看下面的代码吧~

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <queue>
  6 
  7 using namespace std;
  8 const int maxn=1000000+10;
  9 const int INF=2147480000;
 10 
 11 struct Dinic{
 12     int head[maxn],Next[3*maxn],to[3*maxn],cap[3*maxn],flow[3*maxn];
 13     int sz,n,m,s,t;
 14     bool vis[maxn];
 15     int cur[maxn],d[maxn];
 16     void init(int n){
 17         this->n=n;
 18         memset(head,-1,sizeof(head));
 19         this->sz=-1;
 20     }
 21     void add_edge(int a,int b,int c){
 22         ++sz;
 23         to[sz]=b;
 24         cap[sz]=c;flow[sz]=0;
 25         Next[sz]=head[a];head[a]=sz;
 26         ++sz;
 27         to[sz]=a;
 28         cap[sz]=c;flow[sz]=c;
 29         Next[sz]=head[b];head[b]=sz;
 30     }
 31     bool BFS(){
 32         memset(vis,0,sizeof(vis));
 33         queue<int>Q;
 34         vis[s]=1;
 35         d[s]=0;
 36         Q.push(s);
 37         while(!Q.empty()){
 38             int u=Q.front();Q.pop();
 39             for(int i=head[u];i!=-1;i=Next[i]){
 40                 int v=to[i];
 41                 if(!vis[v]&&cap[i]>flow[i]){
 42                     vis[v]=1;
 43                     d[v]=d[u]+1;
 44                     Q.push(v);
 45                 }
 46             }
 47         }
 48         return vis[t];
 49    }
 50     int DFS(int x,int a){
 51         if(x==t||a==0)return a;
 52         int Flow=0,f;
 53         for(int& i=cur[x];i!=-1;i=Next[i]){
 54             int v=to[i];
 55             if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){
 56                 Flow+=f;
 57                 flow[i]+=f;
 58                 flow[i^1]-=f;
 59                 a-=f;
 60                 if(a==0)break;
 61             }
 62         }
 63         return Flow;
 64     }
 65     int Maxflow(int s,int t){
 66         this->s=s,this->t=t;
 67         int Flow=0;
 68         while(BFS()){
 69             for(int i=0;i<=n;i++)
 70              cur[i]=head[i];
 71 
 72             Flow+=DFS(s,INF);
 73         }
 74         return Flow;
 75     }
 76 }dinic;
 77 int R,C,N;
 78 int foot[maxn];
 79 void get_ans(int u){
 80     foot[u]=1;
 81     for(int i=dinic.head[u];i!=-1;i=dinic.Next[i]){
 82         int v=dinic.to[i];
 83         if(!foot[v]&&dinic.cap[i]>dinic.flow[i])
 84             get_ans(v);
 85     }
 86     return;
 87 }
 88 
 89 int main(){
 90     while(scanf("%d%d%d",&R,&C,&N)!=EOF&&(R||C||N)){
 91         memset(foot,0,sizeof(foot));
 92         dinic.init(R+C+5);
 93         int r,c;
 94         for(int i=1;i<=N;i++){
 95             scanf("%d%d",&r,&c);
 96             dinic.add_edge(r,c+R,1);
 97         }
 98         for(int i=1;i<=R;i++)
 99             dinic.add_edge(0,i,1);
100         for(int i=1;i<=C;i++)
101             dinic.add_edge(i+R,C+R+1,1);
102         int ans=dinic.Maxflow(0,C+R+1);
103         printf("%d ",ans);
104         get_ans(0);
105         for(int i=1;i<=R;i++){
106             if(!foot[i]){
107                 printf("r%d ",i);
108             }
109         }
110         for(int i=1;i<=C;i++){
111             int u=i+R;
112             if(foot[u]){
113                 printf("c%d ",i);
114             }
115         }
116         printf("\n");
117     }
118 return 0;
119 }
View Code

 

posted @ 2018-07-13 20:36  蒟蒻LQL  阅读(423)  评论(0)    收藏  举报