题目链接

思路

这道题对于题意的转化很关键。

题目要求的是添上一条边,使得图中最大团的大小变大。给出的边是原图的补集,这就给我们了提示。

因为题目中说,原图中最多有两个团。所以给出的边一定形成了一个二分图。

那么最大团就是新图中的最大独立集。

那么问题就转化成了,在新图中删除一条边,使得新图中的最大独立集变大。

因为最大独立集 = 点数-最大匹配。

所以我们要让最大匹配变小。

考虑删除哪些边会让最大匹配变小。首先肯定要在跑完网络流之后是满流的。然后不能由其他的边来代替。也就是说在残余网络上跑一遍\(tarjan\),满足两段不在同一个强联通分量中的边。

所以做法也就出来了。先建图跑一遍网络流,然后在残余网络上\(tarjan\)一遍。再遍历所有边,找出那些不在两段不在同一个强连通分量中,并且满流的边。

代码

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<queue>
  5. #include<cstdlib>
  6. #include<cmath>
  7. #include<ctime>
  8. #include<algorithm>
  9. #include<bitset>
  10. using namespace std;
  11. typedef long long ll;
  12. #define change(x) x & 1 ? x + 1 : x - 1
  13. const int M = 600010,N = 10010,INF = 1e9 + 7;
  14. ll read() {
  15. ll x=0,f=1;char c=getchar();
  16. while(c<'0'||c>'9') {
  17. if(c=='-') f=-1;
  18. c=getchar();
  19. }
  20. while(c>='0'&&c<='9') {
  21. x=x*10+c-'0';
  22. c=getchar();
  23. }
  24. return x*f;
  25. }
  26. struct node {
  27. int u,v,nxt,w;
  28. }e[M << 1],E[M << 1],ans[M << 1];
  29. int anss;
  30. int head[N],ejs;
  31. void add(int u,int v,int w) {
  32. e[++ejs].u = u;e[ejs].v = v;e[ejs].w = w;e[ejs].nxt = head[u];head[u] = ejs;
  33. e[++ejs].u = v;e[ejs].v = u;e[ejs].w = 0;e[ejs].nxt = head[v];head[v] = ejs;
  34. }
  35. void ADD(int u,int v) {
  36. E[++ejs].u = u;E[ejs].v = v;E[ejs].nxt = head[u];head[u] = ejs;
  37. E[++ejs].v = u;E[ejs].u = v;E[ejs].nxt = head[v];head[v] = ejs;
  38. }
  39. int n,m,S,T;
  40. int lb[N];
  41. void con(int u) {
  42. for(int i = head[u];i;i = E[i].nxt) {
  43. int v = E[i].v;
  44. if(lb[v]) continue;
  45. lb[v] = 3 - lb[u];
  46. con(v);
  47. }
  48. }
  49. int dep[N],dfn[N],inque[N],sta[N],top,low[N],cnt,col[N],coljs;
  50. void tarjan(int u) {
  51. dfn[u] = low[u] = ++cnt;
  52. sta[++top] = u;inque[u] = 1;
  53. for(int i = head[u];i;i = e[i].nxt) {
  54. int v = e[i].v;
  55. if(e[i].w <= 0) continue;
  56. if(!dfn[v]) tarjan(v),low[u] = min(low[u],low[v]);
  57. else if(inque[v]) low[u] = min(low[u],low[v]);
  58. }
  59. if(low[u] == dfn[u]) {
  60. ++coljs;
  61. while(sta[top + 1] != u) {
  62. inque[sta[top]] = 0;
  63. col[sta[top--]] = coljs;
  64. }
  65. }
  66. }
  67. queue<int>q;
  68. int bfs() {
  69. memset(dep,0,sizeof(dep));
  70. while(!q.empty()) q.pop();
  71. q.push(S);dep[S] = 1;
  72. while(!q.empty()) {
  73. int u = q.front();q.pop();
  74. for(int i = head[u];i;i = e[i].nxt) {
  75. int v = e[i].v;
  76. if(dep[v] || e[i].w <= 0) continue;
  77. dep[v] = dep[u] + 1;
  78. if(v == T) return 1;
  79. q.push(v);
  80. }
  81. }
  82. return 0;
  83. }
  84. int dfs(int u,int now) {
  85. if(u == T) return now;
  86. int re = 0;
  87. for(int i = head[u];i;i = e[i].nxt) {
  88. int v = e[i].v;
  89. if(e[i].w <= 0 || dep[v] != dep[u] + 1) continue;
  90. int k = dfs(v,min(now,e[i].w));
  91. if(k) {
  92. e[i].w -= k;
  93. e[change(i)].w += k;
  94. now -= k;
  95. re += k;
  96. if(!now) break;
  97. // return k;
  98. }
  99. }
  100. return re;
  101. }
  102. void dinic() {
  103. while(bfs()) {
  104. int k = dfs(S,INF);
  105. while(k) {
  106. k = dfs(S,INF);
  107. }
  108. }
  109. }
  110. bool tmp(node X,node Y) {
  111. int k1 = min(X.u,X.v),t1 = max(X.u,X.v),k2 = min(Y.u,Y.v),t2 = max(Y.u,Y.v);
  112. return k1 == k2 ? t1 < t2 : k1 < k2;
  113. }
  114. int main() {
  115. n = read(),m = read();
  116. for(int i = 1;i <= m;++i) {
  117. int u = read(),v = read();
  118. ADD(u,v);
  119. }
  120. for(int i = 1;i <= n;++i)
  121. if(!lb[i]) lb[i] = 1,con(i);
  122. memset(head,0,sizeof(head));
  123. ejs = 0;
  124. S = n + 1,T = S + 1;
  125. for(int i = 1;i <= n;++i) {
  126. if(lb[i] == 1) add(S,i,1);
  127. else add(i,T,1);
  128. }
  129. for(int i = 1;i <= m * 2;i += 2) {
  130. if(lb[E[i].u] == 1) add(E[i].u,E[i].v,1);
  131. else add(E[i].v,E[i].u,1);
  132. }
  133. dinic();
  134. for(int i = 1;i <= n;++i) if(!dfn[i]) tarjan(i);
  135. for(int i = 1;i <= ejs;i += 2) {
  136. int u = e[i].u,v = e[i].v;
  137. if(col[u] != col[v] && e[i].w == 0 && e[i].u <= n &&e[i].v <= n) {
  138. ans[++anss] = e[i];
  139. }
  140. }
  141. printf("%d\n",anss);
  142. sort(ans + 1,ans + anss + 1,tmp);
  143. for(int i = 1;i <= anss;++i) {
  144. printf("%d %d\n",min(ans[i].u,ans[i].v),max(ans[i].u,ans[i].v));
  145. }
  146. return 0;
  147. }

luogu3731 新型城市化的更多相关文章

  1. 【Luogu3731】[HAOI2017]新型城市化(网络流,Tarjan)

    [Luogu3731][HAOI2017]新型城市化(网络流,Tarjan) 题面 洛谷 给定一张反图,保证原图能分成不超过两个团,问有多少种加上一条边的方法,使得最大团的个数至少加上\(1\). 题 ...

  2. 求去掉一条边使最小割变小 HAOI2017 新型城市化

    先求最小割,然后对残量网络跑Tarjan.对于所有满流的边,若其两端点不在同一个SCC中,则这条边是满足条件的. 证明见 来源:HAOI2017 新型城市化

  3. Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)

    将未建立贸易关系看成连一条边,那么这显然是个二分图.最大城市群即最大独立集,也即n-最大匹配.现在要求的就是删哪些边会使最大匹配减少,也即求哪些边一定在最大匹配中. 首先范围有点大,当然是跑个dini ...

  4. LOJ2276 [HAOI2017] 新型城市化 【二分图匹配】【tarjan】

    题目分析: 这题出的好! 首先问题肯定是二分图的最大独立集,如果删去某条匹配边之后独立集是否会变大. 跑出最大流之后流满的边就是匹配边. 如果一个匹配边的两个端点在一个强连通分量里,那这条边删掉之后我 ...

  5. Luogu P3731 [HAOI2017]新型城市化

    题目显然可以转化为求每一条边对二分图最大独立集的贡献,二分图最大独立集\(=\)点数\(-\)最大匹配数,我们就有了\(50pts\)做法. 正解的做法是在原图上跑\(Tarjan\),最开始我想复杂 ...

  6. [HAOI2017] 新型城市化

    给出的图中恰包含2个团,则图的补图为一个二分图,其最大独立集为原图的最大团. 我们知道,二分图的最大独立集=V-最小顶点覆盖,最小顶点覆盖=最大匹配. 问题转化为:计算删去后最大匹配减小的边集. 所以 ...

  7. HAOI2017 新型城市化 二分图的最大独立集+最大流+强连通缩点

    题目链接(洛谷):https://www.luogu.org/problemnew/show/P3731 题意概述:给出一张二分图,询问删掉哪些边之后可以使这张二分图的最大独立集变大.N<=10 ...

  8. 【题解】新型城市化 HAOI2017 网络流 二分图最大匹配 强连通分量

    Prelude 好,HAOI2017终于会做一道题了! 传送到洛谷:→_→ 传送到LOJ:←_← 本篇博客链接:(●'◡'●) Solution 首先要读懂题. 考场上我是这样想的QAQ. 我们把每个 ...

  9. loj2276 「HAOI2017」新型城市化

    给出的图是一个二分图(显然--吗),一个图的最大团=其补图的最大独立集,因此二分图的最大独立集就是补图的最大团. 欲使补图最大团变大,则要最大独立集变大.二分图最大独立集=点数-最小点覆盖.最小点覆盖 ...

随机推荐

  1. JSON Support in PostgreSQL and Entity Framework

    JSON 和JSONB的区别(What's difference between JSON and JSONB data type in PosgresSQL?) When should be use ...

  2. CodeForces 126B Password

    题目链接:http://codeforces.com/problemset/problem/126/B 题目大意: 多组数据每组给定1个字符串S,问是否存在S的一个尽量长的子串,同时是S的前缀和后缀, ...

  3. Python基础知识2-内置数据结构(下)

    bytes.bytearray #思考下面例子: a = 1 b = a print(a == b)#True print(a is b)#True print(id(a) is id(b))#Fal ...

  4. countByValue

    [1,2,3,3]的RDD rdd.foreach(println)---------------------1 2 3 3

  5. ABP实践学习

    一.

  6. python工具使用笔记

    1.pip pip是Python官方推荐的包管理工具,在doc界面直接使用pip或者pip3命令即可,例如安装gensim: C:\Users\kayan.sjc>pip3 install -- ...

  7. 01.javascript之数据类型

    1.数据类型 JavaScript一共有六种数据类型.(ES6新增了第七种Symbol类型的值) 数值(Number) 字符串(String) 布尔值(boolean) undefined null ...

  8. js中session操作

    // 保存数据到sessionStorage sessionStorage.setItem('key', 'value');   // 从sessionStorage获取数据 var data = s ...

  9. Vue——服务器上部署vue.js

    服务器版本 [root@izuf63g0jydq42k49eo7zcz ~]# uname -a Linux izuf63g0jydq42k49eo7zcz -.el7.x86_64 # SMP Tu ...

  10. HDU4035 Maze 【树形DP】【期望DP】

    题目分析: 以前一直不会这个方法, 我好菜啊. 转移分为三个部分,一个是直接成功,一个是转移到E1,还有一个是转移到自己周围的一圈儿点. 如果是叶子那么只能转移到父亲,如果不是叶子可以把非叶子的转移代 ...