我到底怎么建的图为啥要开这么大的数组啊?!

神题神题,本来以为图论出不出什么花来了。

首先要理解‘团’的概念,简单来说就是无向图的一个完全子图,相关概念详见度娘。

所以关于团一般都是NP问题,只有二分图例外。而题目中有这样一句话“n座城市可以恰好被划分为不超过两个城市群”,并且给出的是没有的边,也就是这个图的补图,两个团就很显然表示这个补图是个二分图(我一开始还考虑1个团咋整后来发现根本不用整= =),模型就变成了二分图的最大独立集,考虑最大独立集=n-最大匹配,那么只要求出删掉哪些边会让最大匹配减少,也就是哪些边一定在最大匹配里即可。

先看一下大概步骤:

1.黑白染色,建出二分图(在这里用dinic求最大匹配因为懒得重建图这样tarjan直接按着满流边跑即可

2.dinic

3.顺着满流边用tarjan求scc

4.把两端不在同一个强连通分量里、两端不是s或t、满流的边加进ans数组里,排个序输出

为什么要这样做呢?

首先没满流的边一定不在最大匹配里就不说了。

然后对于两端能缩到一个scc里的边,一个点的一入一出都可能与它匹配,所以不一定在最大匹配里。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<queue>
  4. #include<cstring>
  5. #include<algorithm>
  6. using namespace std;
  7. const int N=1000005,inf=1e9;
  8. int n,m,h[N],cnt,c[N],s,t,le[N],dfn[N],low[N],tot,st[N],top,bl[N],con,co,x[N],y[N];
  9. bool v[N];
  10. struct qwe
  11. {
  12. int ne,no,to,va;
  13. }e[N*20];
  14. struct qw
  15. {
  16. int x,y;
  17. qw(const int X=0,const int Y=0)
  18. {
  19. x=X,y=Y;
  20. if(x>y)
  21. swap(x,y);
  22. }
  23. }ans[N];
  24. bool cmp(const qw &a,const qw &b)
  25. {
  26. return a.x<b.x||(a.x==b.x&&a.y<b.y);
  27. }
  28. int read()
  29. {
  30. int r=0,f=1;
  31. char p=getchar();
  32. while(p>'9'||p<'0')
  33. {
  34. if(p=='-')
  35. f=-1;
  36. p=getchar();
  37. }
  38. while(p>='0'&&p<='9')
  39. {
  40. r=r*10+p-48;
  41. p=getchar();
  42. }
  43. return r*f;
  44. }
  45. void add(int u,int v,int w)
  46. {
  47. cnt++;
  48. e[cnt].ne=h[u];
  49. e[cnt].no=u;
  50. e[cnt].to=v;
  51. e[cnt].va=w;
  52. h[u]=cnt;
  53. }
  54. void ins(int u,int v,int w)
  55. {//cout<<u<<" "<<v<<endl;
  56. add(u,v,w);
  57. add(v,u,0);
  58. }
  59. void dfss(int u,int col)
  60. {
  61. c[u]=col;
  62. v[u]=1;
  63. for(int i=h[u];i;i=e[i].ne)
  64. if(!v[e[i].to])
  65. dfss(e[i].to,col^1);
  66. }
  67. bool bfs()
  68. {
  69. queue<int>q;
  70. memset(le,0,sizeof(le));
  71. le[s]=1;
  72. q.push(s);
  73. while(!q.empty())
  74. {
  75. int u=q.front();
  76. q.pop();
  77. for(int i=h[u];i;i=e[i].ne)
  78. if(e[i].va>0&&!le[e[i].to])
  79. {
  80. le[e[i].to]=le[u]+1;
  81. q.push(e[i].to);
  82. }
  83. }
  84. return le[t];
  85. }
  86. int dfs(int u,int f)
  87. {//cout<<u<<" "<<f<<endl;
  88. if(!f||u==t)
  89. return f;
  90. int us=0;
  91. for(int i=h[u];i&&us<f;i=e[i].ne)
  92. if(le[e[i].to]==le[u]+1&&e[i].va>0)
  93. {
  94. int t=dfs(e[i].to,min(e[i].va,f-us));
  95. e[i].va-=t;
  96. e[i^1].va+=t;
  97. us+=t;
  98. }
  99. if(!us)
  100. le[u]=0;
  101. return us;
  102. }
  103. void dinic()
  104. {
  105. while(bfs())
  106. dfs(s,inf);
  107. }
  108. void tarjan(int u)
  109. {
  110. dfn[u]=low[u]=++tot;
  111. v[st[++top]=u]=1;
  112. for(int i=h[u];i;i=e[i].ne)
  113. if(!e[i].va)
  114. {
  115. if(!dfn[e[i].to])
  116. {
  117. tarjan(e[i].to);
  118. low[u]=min(low[u],low[e[i].to]);
  119. }
  120. else if(v[e[i].to])
  121. low[u]=min(low[u],dfn[e[i].to]);
  122. }
  123. if(dfn[u]==low[u])
  124. {
  125. con++;
  126. while(st[top]!=u)
  127. {
  128. bl[st[top]]=con;
  129. v[st[top--]]=0;
  130. }
  131. bl[st[top]]=con;
  132. v[st[top--]]=0;
  133. }
  134. }
  135. int main()
  136. {
  137. n=read(),m=read();
  138. for(int i=1;i<=m;i++)
  139. {
  140. x[i]=read(),y[i]=read();
  141. add(x[i],y[i],0);add(y[i],x[i],1);
  142. }
  143. for(int i=1;i<=n;i++)
  144. if(!v[i])
  145. dfss(i,2);
  146. memset(h,0,sizeof(h));
  147. cnt=1;
  148. s=0,t=n+1;
  149. for(int i=1;i<=n;i++)
  150. {
  151. if(c[i]==2)
  152. ins(s,i,1);
  153. else
  154. ins(i,t,1);
  155. }
  156. for(int i=1;i<=m;i++)
  157. {
  158. if(c[x[i]]==2)
  159. ins(x[i],y[i],1);
  160. else
  161. ins(y[i],x[i],1);
  162. }//cout<<"OKBUILD"<<endl;
  163. dinic();//cout<<"OKDINIC"<<endl;
  164. memset(v,0,sizeof(v));
  165. for(int i=1;i<=n;i++)
  166. if(!dfn[i])
  167. tarjan(i);
  168. for(int i=2;i<=cnt;i+=2)
  169. if(!e[i].va&&bl[e[i].no]!=bl[e[i].to]&&e[i].no!=s&&e[i].no!=t&&e[i].to!=s&&e[i].to!=t)
  170. ans[++co]=qw(e[i].no,e[i].to);
  171. sort(ans+1,ans+1+co,cmp);
  172. printf("%d\n",co);
  173. for(int i=1;i<=co;i++)
  174. printf("%d %d\n",ans[i].x,ans[i].y);
  175. return 0;
  176. }

洛谷 P3731 [HAOI2017]新型城市化【最大流(二分图匹配)+tarjan】的更多相关文章

  1. P3731 [HAOI2017]新型城市化(tarjan+网络流)

    洛谷 题意: 给出两个最大团的补图,现在要求增加一条边,使得最大最大团个数增加至少\(1\). 思路: 我们求出团的补图,问题可以转换为:对于一个二分图,选择删掉一条边,能够增大其最大独立集的点集数. ...

  2. 洛谷P2756 飞行员配对方案问题(二分图匹配)

    传送门 一个基础的二分图匹配(虽然今天才学会) 因为不会匈牙利算法只好用网络流做 先新建一个超级源和超级汇,源往所有左边的点连边,所有右边的点往汇连边 然后跑一边最大流就好了 顺便记录一下匹配到谁就好 ...

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

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

  4. 洛谷P4589 [TJOI2018]智力竞赛(二分答案 二分图匹配)

    题意 题目链接 给出一个带权有向图,选出n + 1n+1条链,问能否全部点覆盖,如果不能,问不能覆盖的点权最小值最大是多少 Sol TJOI怎么净出板子题 二分答案之后直接二分图匹配check一下. ...

  5. 【洛谷 P1129】 [ZJOI2007]矩阵游戏 (二分图匹配)

    题目链接 看到题目肯定首先会想到搜索. 然鹅数据范围\(n<=200\)这么大(其实也不算太大),肯定是不行的. 如果\((i,j)\)是\(1\),从\(i\)向\(j\)连一条边,表示第\( ...

  6. 洛谷P2526 [SHOI2001]小狗散步(二分图匹配)

    题目背景 Grant喜欢带着他的小狗Pandog散步.Grant以一定的速度沿着固定路线走,该路线可能自交.Pandog喜欢游览沿途的景点,不过会在给定的N个点和主人相遇.小狗和主人同时从(X1,Y1 ...

  7. 洛谷 P2055 [ ZJOI 2009 ] 假期的宿舍 —— 二分图匹配

    题目:https://www.luogu.org/problemnew/show/P2055 二分图匹配: 注意要连边的话对方必须有床! 代码如下: #include<iostream> ...

  8. 【洛谷P1963】[NOI2009]变换序列(二分图匹配)

    传送门 题意: 现有一个\(0\)到\(n-1\)的排列\(T\),定义距离\(D(x,y)=min\{|x-y|,N-|x-y|\}\). 现在给出\(D(i, T_i)\),输出字典序最小的符合条 ...

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

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

随机推荐

  1. 导师高茂源:用CODEX创新方法破解西方创新“秘密”(转)

    高茂源,“CODEX创新体系”的创立者,精一学社的创业导师.“CODEX”是Copy.Optimize.Dimension.Ecosystem.Extra五个单词的缩写,该体系精炼了现在世界上流行的创 ...

  2. com.sun.xxx.utils不存在问题的解决

    com.sun.org.apache.xml.internal.security.utils does not exist问题的解决 在网上找个很多的答案,但我的问题没有解决,睡一晚上后,被我误打误撞 ...

  3. jquery 关于ajax 及其son

    <%@ page language="java" pageEncoding="UTF-8"%><%@include file="/c ...

  4. 下一代的中间件必须是支持docker规范的

    下一代的中间件必须是支持docker规范的,这是中间件技术走向标准规范化的必经之路. 什么是 Docker? 答案是:Docker 是下一代的云计算模式.Docker 是下一代云计算的主流趋势. Do ...

  5. SAS学习笔记 - R的数据操作

    1.对象 1.1 对象及其内在属性 R中的处理数据就是对象,每个对象可以包含多个元素.对象有两个内在属性:类型和长度.类型是对象元素的基本种类,共四种:数值型,字符型,复数型和逻辑型.对象的类型和长度 ...

  6. swift-for循环遍历,遍历字典,循环生成数组

    // Playground - noun: a place where people can play import UIKit //--------------------------------- ...

  7. CxImage的编译及简单使用举例

    1.  从http://sourceforge.net/projects/cximage/下载最新的CxImage 702源代码. 2.  解压缩后,以管理员身份打开CxImageFull_vc10. ...

  8. 在linux命令行中编译和运行java文件

    同时加载编译多个jar包和java文件 在个人平常使用或者当我们把代码部署到linux服务器上的时候,我们经常需要通过命令行编译和运行java文件,网上关于这个的方法大多是通过 javac -cp f ...

  9. 大数据处理之道 (htmlparser获取数据&lt;一&gt;)

    一:简单介绍 (1)HTML Parser是一个用于解析Html的Java的库.可採用线性或嵌套两种方式.主要用于网页的转换或提取,他有一些特性:过滤器filter,遍历器visitors,通常的标签 ...

  10. C++问题记录

    问题idx: 1) 怎么在VS2010下新建一个像VC6.0 中那样的控制台C++程序. cdate: 2014-4-24 A1: VC6.0 对标准C++集的支持不是太好, VS2010也有一些吧, ...