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

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

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

所以关于团一般都是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. JFinal Weixin 1.5 发布,微信极速 SDK

    原文:http://www.oschina.net/news/67980/jfinal-weixin-1-5-released JFinal Weixin 1.5 大幅完善了对微信公众平台API的支持 ...

  2. T2627 村村通 codevs

    http://codevs.cn/problem/2627/  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold 题目描述 Description 农民约翰被选为他们 ...

  3. DELPHI最新的产品路线图

    1)根据众多像您一样的客户要求,我们改为一年一个重大版本及更多更新.这个计划回到一年发布周期并提供额外的2或3个包含附加功能及支持期间发布的新版操作系统的更新. 2)在 RAD Studio  10. ...

  4. 系统优化(一)Maven打包同一个jar有不同的:版本号+时间戳(解决思路)

    解决:maven仓库的ear里面有非常多个同样的jar(仅仅是包括不同的:版本号+时间戳) 问题描写叙述: 发现ear里面有非常多个同样的jar,仅仅是包括不同的:版本号+时间戳,例如以下图所看到的: ...

  5. There is no PasswordEncoder mapped for the id "null"

    There is no PasswordEncoder mapped for the id "null" 学习了:https://blog.csdn.net/dream_an/ar ...

  6. 选带傅里叶变换(zoom-fft)

    选带傅里叶变换的原理大家能够看书.大致的步骤为 移频 (将选带的中心频率移动到零频) 数字低通滤波器  (防止频率混叠) 又一次採样  (将採样的数据再次间隔採样,间隔的数据取决于分析的带宽,就是放大 ...

  7. 【Mongodb教程 第十三课 】PHP mongodb 的增删改查使用

    <pre> <?php #phpinfo();die; #其他链接方式 #$conn=new Mongo(); #连接本地主机,默认端口. #$conn=new Mongo(&quo ...

  8. java 报错非法的前向引用

    今天在看<thinking in java>的时候,第四章提到了非法的前向引用,于是自己试了一下,书中的例子倒是一下就明白了,但是自己写的一个却怎么也不明白,于是上网问了一位前辈,终于明白 ...

  9. 浅谈JavaScript的面向对象程序设计(三)

    前面已经对JavaScript的面向对象程序设计作了简单的介绍,包括了对象的属性.对象的工厂模式.构造函数和原型等.通过介绍,这些创建对象的方法依然有不少优化和改进的地方. 组合使用构造函数模式和原型 ...

  10. 嵌入式开发之davinci--- mcfw框架介绍

    整体上mcfw框架如下图 从中可见其层次是清楚的,link实在基本的驱动之上的,而mcfw是在link之上的api,是通过link来实现相应的功能.可见link是框架中承上启下的层次,通过link来实 ...