[关闭]
@y20070316 2017-10-03T01:14:33.000000Z 字数 2249 阅读 1208

【xsy1648】最小点覆盖 二分图最小点覆盖

题目 网络流


题意

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

  现在给定一个二分图,请你把图中的点分成三个集合:
  如果在任何一种最小点覆盖中都不包含这个点,则认为该点属于 集合。
  如果在任何一种最小点覆盖中都包含这个点,则认为该点属于 集合。
  如果一个点既不属于 集合,又不属于 集合,则认为该点属于 集合。

  

分析

  首先我们有 Konig定理


  证明:
   ① 构造: 从左边未匹配的点开始,找交错轨,将所有的点标记。取左边所有未标记的点,和右边所有标记的点。
   ② 证明构造出来的点集大小恰好为最大匹配数
   ③ 证明构造出来的点集是点覆盖集
   ④ 证明点覆盖集的大小取到最小

  根据上面点覆盖集的理论,差不多就可以做这一道题了。
  我们先跑出一个匹配。一个不在任意一个匹配上的点,一定不在点覆盖集中。因为我们从这个点可以跑出若干条交错轨,交错轨的点数为奇数,且左边的点比右边的点多一个,所以一定选左边的点。
  由于一种匹配方案对应一种点覆盖集的构造方案,一条匹配边有且仅有一个点在点覆盖集上,所以与不在匹配上的点相邻的一定是点覆盖集中的点。
  也正是因为如此,与一定在点覆盖集中的点匹配的点一定不再点覆盖集中
  我们BFS一次就好了,没有遍历到的点就可能在,可能不在了。

实现

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <cctype>
  5. using namespace std;
  6. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  7. const int N=2005;
  8. const int E=2000005;
  9. int n,m,k;
  10. struct Ed {
  11. int v,nx;
  12. inline Ed(int _v=0,int _nx=0):v(_v),nx(_nx){}
  13. }mp[E];
  14. int tot,hd[N];
  15. int v[N];
  16. int mat[N];
  17. int col[N];
  18. namespace input {
  19. const int SIZE=2000000;
  20. char buffer[SIZE];
  21. char *head=buffer+SIZE;
  22. char *tail=head;
  23. inline char getchr(void) {
  24. if (head==tail) {
  25. fread(buffer,1,SIZE,stdin);
  26. head=buffer;
  27. }
  28. return *head++;
  29. }
  30. inline int rd(void) {
  31. int x=0,f=1; char c=getchr();
  32. for (;!isdigit(c);c=getchr()) if (c=='-') f=-1;
  33. for (;isdigit(c);c=getchr()) x=x*10+c-'0';
  34. return x*f;
  35. }
  36. }
  37. using input::rd;
  38. inline void Ins(int u,int v) {
  39. mp[++tot]=Ed(v,hd[u]); hd[u]=tot;
  40. mp[++tot]=Ed(u,hd[v]); hd[v]=tot;
  41. }
  42. int Hungary(int x) {
  43. for (int k=hd[x];k>0;k=mp[k].nx)
  44. if (!v[mp[k].v]) {
  45. v[mp[k].v]=1;
  46. if (!mat[mp[k].v]||Hungary(mat[mp[k].v])) {
  47. mat[mp[k].v]=x;
  48. mat[x]=mp[k].v;
  49. return 1;
  50. }
  51. }
  52. return 0;
  53. }
  54. void BFS(void) {
  55. static int q[N]; int qh=0,qt=0;
  56. F(i,1,n+m)
  57. if (!mat[i]) {
  58. col[i]=1;
  59. q[++qt]=i;
  60. }
  61. while (qh!=qt) {
  62. int x=q[++qh];
  63. if (col[x]==1) {
  64. for (int k=hd[x];k>0;k=mp[k].nx)
  65. if (!col[mp[k].v]) {
  66. col[mp[k].v]=2;
  67. q[++qt]=mp[k].v;
  68. }
  69. }
  70. else if (col[x]==2) {
  71. if (mat[x]>0&&!col[mat[x]]) {
  72. col[mat[x]]=1;
  73. q[++qt]=mat[x];
  74. }
  75. }
  76. }
  77. }
  78. void Print(void) {
  79. static char s[N];
  80. F(i,1,n)
  81. if (!col[i]) s[i]='E';
  82. else if (col[i]==1) s[i]='N';
  83. else if (col[i]==2) s[i]='A';
  84. s[n+1]=0;
  85. printf("%s\n",s+1);
  86. F(i,n+1,n+m)
  87. if (!col[i]) s[i-n]='E';
  88. else if (col[i]==1) s[i-n]='N';
  89. else if (col[i]==2) s[i-n]='A';
  90. s[m+1]=0;
  91. printf("%s\n",s+1);
  92. }
  93. int main(void) {
  94. #ifndef ONLINE_JUDGE
  95. freopen("sdchr.in","r",stdin);
  96. freopen("sdchr.out","w",stdout);
  97. #endif
  98. cin>>n>>m>>k;
  99. F(i,1,k) {
  100. int x=rd(),y=rd();
  101. Ins(x,n+y);
  102. }
  103. F(i,1,n+m) if (!mat[i]) {
  104. memset(v,0,sizeof v);
  105. Hungary(i);
  106. }
  107. memset(col,0,sizeof col);
  108. BFS();
  109. Print();
  110. return 0;
  111. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注