码迷,mamicode.com
首页 > 其他好文 > 详细

【noip模拟】最小点覆盖

时间:2017-10-03 22:22:50      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:gif   tar   顶点   www.   rom   ++   neu   close   字符   

Time Limit: 1000ms      Memory Limit: 128MB  

Description

最小点覆盖是指在二分图中,用最小的点集覆盖所有的边。当然,一个二分图的最小点覆盖可能有很多种。

现在给定一个二分图,请你把图中的点分成三个集合:

如果在任何一种最小点覆盖中都不包含这个点,则认为该点属于N集合。

如果在任何一种最小点覆盖中都包含这个点,则认为该点属于A集合。

如果一个点既不属于N集合,又不属于A集合,则认为该点属于E集合。

 

Input

第一行包含三个整数n, m, k,分别表示二分图A侧点的数量,二分图B侧点的数量,边的数量。

接下来k行,每行两个整数i, j,分别表示二分图A侧第i号点与二分图B侧第j号点有连边。

数据保证无重边。

 

Output

第一行输出一个长度为n的字符串,其中第i个字符表示二分图A侧第i个点所属的集合。

第二行输出一个长度为m的字符串,其中第i个字符表示二分图B侧第i个点所属的集合。

 

Sample Input

11 9 22

1 1

1 2

1 3

1 8

1 9

2 1

2 3

3 2

3 4

4 3

4 5

5 2

5 4

5 6

6 6

6 7

7 5

7 7

8 7

9 7

10 7

11 7

 

Sample Output

AEEEEEENNNN

EEEEEEANN

 

HINT

对于10%的数据,$1≤n,m≤5$

对于40%的数据,$1≤n,m≤100$

对于100%的数据,$1≤n,m≤1000, 0≤k≤n∗m$

 

 

[吐槽]

  场上?嗯。。大眼瞪小眼qwq

 

[题解]

  嗯首先码一下最小点覆盖的相关知识

  http://www.matrix67.com/blog/archives/116 (二分图最大匹配的König定理及其证明

  (所以说其实我也很想知道为什么那个o上面有两个点啊哈哈哈哈)

  

  嗯还是把自己对于上面那篇东西的理解写一下吧整理整理qwq

  这题要按照最小点覆盖是否包含一个点来分类,所以先想一下怎么得到最小点覆盖的一种可行方案

 

  König定理

  一个二分图中最大的匹配数=该图中最小点覆盖数

  嗯首先还是先把定义搬出来吧

  点覆盖:就是一个点集,满足该图的所有边都有至少一个顶点在这个点集中,点集大小最小的成为最小点覆盖

  

  证明的话稍微整理一下(learn from matrix67%%%)

  假设我们现在已经跑出了一个最大匹配,匹配数为$m$,考虑构造一种点覆盖的可行方案

   一个简单的想法:

  我们按照一种方式给这堆点打上标记,以B部分中所有没有被匹配到的点为起点,顺着匈牙利算法中的交错轨(也就是匹配边和非匹配边交替着走)遍历直到不能走下去了为止,并给沿路上的点全部打上标记

  现在我们将B部分中没有打上标记的点和A部分中打上标记的点变成一个点集

  这个点集就是一种可行的点覆盖,而且是最小点覆盖

 

  为啥?

  我们先将交错轨标号所有的一些奇妙性质列出来再进行证明会比较方便一点

  对于一条在交错轨上的边$(u,v)$,必定满足:

  1.$u,v$均为标号点

  2.若该边为匹配边,则遍历时先走到$u$再走到$v$,即从A部分到B部分

  3.若改变为非匹配边,则遍历时先走到$v$再走到$u$,即从B部分走到A部分

 

  首先证明一下这是一个点覆盖

  我们可以把边分为两类,一类是在某条交错轨上的边,一类不在

  对于在交错轨上面的边,显然我可以通过选取A部分中打上标记也就是遍历到的点来覆盖掉

  而对于不在交错轨上且没有被覆盖到的边,它在B部分的端点一定是没有被标记的

  (否则就说明其在A部分的端点一定是没有被标记的,

  而这种边是不可能存在的,用反证法

  设存在一条边$(u,v)$,$u$没被标记,$v$被标记,

  则$v$应该被交错轨经过

  若这条边是匹配边,则一定是由$u$走到$v$,也就是说$v$的标记一定来自$u$,

  因此$u$也应该有标记,矛盾

  若这条边是非匹配边,则到$v$的交错轨可以继续走下去

  这条边也应该在交错轨上,矛盾

  综上,不存在这种边)

  所以这种选法就一定可以保证所有的边都被覆盖到啦

 

  第二,证明一下这个点覆盖的大小$=m$

  首先看我们选的用来覆盖交错轨上的边的点

  因为我们在标记的时候走的是一段段的交错轨,并且我们的起点是在右边

  所以左边的A部分中被标记的点的个数必定与交错轨中匹配边的个数相等

 

  接着看剩下的部分

  由于交错轨标号方式,交错轨上的边的两端的点必定都是被标记的点

  换句话来说就是非交错轨上的且没有被覆盖到的边的右端点肯定连到的是未被标记的B部分的点

  而每个未被标记的B部分的点必定会连且只会连出一条匹配边(继续反证嗯,比较简单不写了)

  所以数量也是相同的  
  

  所以两个加一下就是$m$啦

 

  最后,证明这是最小点覆盖

  嗯。。一句话搞定:覆盖$m$条匹配边最少都要$m$个点,所以当然就是最小的啦

  搞掂捞面

 

  回到这道题

  所以说前面讲了这么多好像现在才进入正题。。

  嗯不管了

  然后我们就可以得出一个结论:

  如果一个点没有任何一条匹配边连到,那么这个点肯定不在最小点覆盖中

  从而与它相连的点必定要在最小点覆盖中(不然这两点之间的连边就不能覆盖到了)

  而对于一个必定在最小点覆盖中的点,与它的匹配点必定不在最小点覆盖中

 

  然后就这样顺着遍历同时标记就好啦

  对于那些没有被标记到的点,肯定就是属于E的啦

  好的于是在漫长的铺垫之后这题终于解决啦ovo

 

[一些细节]

  首先。。要用long long

  其次。。注意边数

 

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int MAXN=1010*2;
 6 struct xxx
 7 {
 8     int y,next;
 9 }a[1010*1010*2];
10 char mark[MAXN];
11 bool vis[MAXN];
12 int h[MAXN],match[MAXN];
13 int n,m,tot,k,ans;
14 int add(int x,int y);
15 bool dfs(int x);
16 int solve();
17 int work(int x,int op);
18 
19 int main()
20 {
21 //    freopen("a.in","r",stdin);
22 
23     int x,y;
24     scanf("%d%d%d",&n,&m,&k);
25     memset(h,-1,sizeof(h));
26     tot=0;
27     for (int i=1;i<=k;++i)
28     {
29         scanf("%d%d",&x,&y);
30         add(x,n+y); add(n+y,x);
31     }
32     memset(match,0,sizeof(match));
33     for (int i=1;i<=n+m;++i) mark[i]=E;
34     for (int i=1;i<=n;++i)
35         if (!match[i])
36         {
37             memset(vis,false,sizeof(vis));
38             if (dfs(i)) ++ans;
39         }
40 //    for (int i=1;i<=n;++i) printf("%d ",match[i]-n);
41     solve();
42     for (int i=1;i<=n;++i) printf("%c",mark[i]);
43     printf("\n");
44     for (int i=n+1;i<=n+m;++i) printf("%c",mark[i]);
45 }
46 
47 int add(int x,int y)
48 {
49     a[++tot].y=y; a[tot].next=h[x]; h[x]=tot;
50 }
51 
52 bool dfs(int x)
53 {
54     int u;
55     for (int i=h[x];i!=-1;i=a[i].next)
56     {
57         u=a[i].y;
58         if (vis[u]) continue;
59         vis[u]=true;
60         if (!match[u]||dfs(match[u]))
61         {
62             match[x]=u;
63             match[u]=x;
64             return true;
65         }
66     }
67     return false;
68 }
69 
70 int solve()
71 {
72     for (int i=1;i<=n+m;++i)
73     {
74         if (!match[i]) 
75             mark[i]=N,work(i,0);
76     }
77 }
78 
79 int work(int x,int op)
80 {
81     int u;
82     if (op==1) 
83     {
84         mark[x]=A;
85         work(match[x],0);
86         return 0;
87     }
88     mark[x]=N;
89     for (int i=h[x];i!=-1;i=a[i].next)
90     {
91         u=a[i].y;
92         if (mark[u]==E) work(u,1);
93     }
94 }
挫挫滴代码

 

【noip模拟】最小点覆盖

标签:gif   tar   顶点   www.   rom   ++   neu   close   字符   

原文地址:http://www.cnblogs.com/yoyoball/p/7624368.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!