Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)
将未建立贸易关系看成连一条边,那么这显然是个二分图。最大城市群即最大独立集,也即n-最大匹配。现在要求的就是删哪些边会使最大匹配减少,也即求哪些边一定在最大匹配中。
首先范围有点大,当然是跑个dinic,转化成最大流。会使最大流减少的边相当于可能在最小割中的边,因为删掉它就相当于无代价的割掉了一条边。那么用曾经看到过的结论就可以了:当且仅当该边满流且残余网络(包括反向边)中该边两端点处于不同SCC时,该边可能在最小割中。不太会证。于是tarjan一发就可以了。注意不要把开始给的图和网络流建图搞混。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 10010
#define M 300010
#define S 0
#define T 10001
char getc(){char c=getchar();while (c==||c==||c==) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,p[N],t=-,color[N],ans;
int d[N],q[N],cur[N];
struct data{int to,nxt,cap,flow;
}edge[M<<];
struct data2
{
int x,y;
bool operator <(const data2&a) const
{
return x<a.x||x==a.x&&y<a.y;
}
}v[M];
void addedge(int x,int y,int z)
{
t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=,p[x]=t;
t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=,edge[t].flow=,p[y]=t;
}
void paint(int k)
{
for (int i=p[k];~i;i=edge[i].nxt)
if (color[edge[i].to]==-)
{
color[edge[i].to]=color[k]^;
paint(edge[i].to);
}
}
bool bfs()
{
int head=,tail=;q[]=S;
memset(d,,sizeof(d));d[S]=;
do
{
int x=q[++head];
for (int i=p[x];~i;i=edge[i].nxt)
if (d[edge[i].to]==-&&edge[i].flow<edge[i].cap)
{
d[edge[i].to]=d[x]+;
q[++tail]=edge[i].to;
}
}while (head<tail);
return ~d[T];
}
int work(int k,int f)
{
if (k==T) return f;
int used=;
for (int i=cur[k];~i;i=edge[i].nxt)
if (d[k]+==d[edge[i].to])
{
int w=work(edge[i].to,min(f-used,edge[i].cap-edge[i].flow));
edge[i].flow+=w,edge[i^].flow-=w;
if (edge[i].flow<edge[i].cap) cur[k]=i;
used+=w;if (used==f) return f;
}
if (used==) d[k]=-;
return used;
}
void dinic()
{
while (bfs())
{
memcpy(cur,p,sizeof(p));
work(S,N);
}
}
namespace newgraph
{
int dfn[N]={},low[N]={},stk[N],id[N],top=,cnt=,tot=,t=,p[N]={},ans=;
bool flag[N];
struct data{int to,nxt;}edge[M];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void tarjan(int k)
{
dfn[k]=low[k]=++cnt;
stk[++top]=k;flag[k]=;
for (int i=p[k];i;i=edge[i].nxt)
if (!dfn[edge[i].to]) tarjan(edge[i].to),low[k]=min(low[k],low[edge[i].to]);
else if (flag[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
if (dfn[k]==low[k])
{
tot++;
while (stk[top]!=k)
{
flag[stk[top]]=;
id[stk[top]]=tot;
top--;
}
flag[k]=;id[k]=tot;top--;
}
}
void work()
{
for (int i=;i<=n;i++)
if (!dfn[i]) tarjan(i);
if (!dfn[T]) tarjan(T);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
memset(p,,sizeof(p));
for (int i=;i<=m;i++)
{
int x=read(),y=read();
addedge(x,y,);
}
memset(color,,sizeof(color));
for (int i=;i<=n;i++) if (color[i]==-) color[i]=,paint(i);
for (int i=;i<=t;i++) edge[i].cap=color[edge[i^].to];
for (int i=;i<=n;i++)
if (color[i]) addedge(S,i,);
else addedge(i,T,);
dinic();
for (int i=;i<=t;i++)
if (edge[i].flow<edge[i].cap) newgraph::addedge(edge[i^].to,edge[i].to);
newgraph::work();
for (int i=;i<=t;i++)
if (edge[i].cap==&&edge[i].flow==edge[i].cap&&edge[i^].to!=S&&edge[i].to!=T&&newgraph::id[edge[i^].to]!=newgraph::id[edge[i].to])
ans++,v[ans].x=min(edge[i^].to,edge[i].to),v[ans].y=max(edge[i^].to,edge[i].to);
sort(v+,v+ans+);
cout<<ans<<endl;
for (int i=;i<=ans;i++) printf("%d %d\n",v[i].x,v[i].y);
return ;
}
Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)的更多相关文章
- poj1904 二分图匹配+强连通分量
http://poj.org/problem?id=1904 Description Once upon a time there lived a king and he had N sons. An ...
- HAOI2017 新型城市化 二分图的最大独立集+最大流+强连通缩点
题目链接(洛谷):https://www.luogu.org/problemnew/show/P3731 题意概述:给出一张二分图,询问删掉哪些边之后可以使这张二分图的最大独立集变大.N<=10 ...
- UESTC 898 方老师和缘分 --二分图匹配+强连通分量
这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u-> ...
- 【Luogu3731】[HAOI2017]新型城市化(网络流,Tarjan)
[Luogu3731][HAOI2017]新型城市化(网络流,Tarjan) 题面 洛谷 给定一张反图,保证原图能分成不超过两个团,问有多少种加上一条边的方法,使得最大团的个数至少加上\(1\). 题 ...
- 求去掉一条边使最小割变小 HAOI2017 新型城市化
先求最小割,然后对残量网络跑Tarjan.对于所有满流的边,若其两端点不在同一个SCC中,则这条边是满足条件的. 证明见 来源:HAOI2017 新型城市化
- 【题解】新型城市化 HAOI2017 网络流 二分图最大匹配 强连通分量
Prelude 好,HAOI2017终于会做一道题了! 传送到洛谷:→_→ 传送到LOJ:←_← 本篇博客链接:(●'◡'●) Solution 首先要读懂题. 考场上我是这样想的QAQ. 我们把每个 ...
- LOJ2276 [HAOI2017] 新型城市化 【二分图匹配】【tarjan】
题目分析: 这题出的好! 首先问题肯定是二分图的最大独立集,如果删去某条匹配边之后独立集是否会变大. 跑出最大流之后流满的边就是匹配边. 如果一个匹配边的两个端点在一个强连通分量里,那这条边删掉之后我 ...
- 洛谷 P3731 [HAOI2017]新型城市化【最大流(二分图匹配)+tarjan】
我到底怎么建的图为啥要开这么大的数组啊?! 神题神题,本来以为图论出不出什么花来了. 首先要理解'团'的概念,简单来说就是无向图的一个完全子图,相关概念详见度娘. 所以关于团一般都是NP问题,只有二分 ...
- hdu 4685 二分匹配+强连通分量
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 题解: 这一题是poj 1904的加强版,poj 1904王子和公主的人数是一样多的,并且给出 ...
随机推荐
- javascript中几种this指向问题
javascript中几种this指向问题 首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用 函数作为全局对象调用,this指向 ...
- maven-生命周期与插件
Maven的生命周期是抽象的,具体的操作由插件实现,类似于java的模板设计模式. 1.生命周期 认识生命周期 maven有clean.default.site三种生命周期,每种生命周期都包含一些阶段 ...
- 学习python第一天 pycharm设置
print(“hello,world”) pycharm设置 1. 选择python 解析器,目的是确定pycharm 的运行环境. 方法: File-->Settings-->Proje ...
- Java学习笔记一:三步搭建Java开发环境
Java开发环境搭建 一:安装JDK: 1.下载地址:http://www.oracle.com/technetwork/java/javase/downloads 非常显眼的下载界面 2.点击下载后 ...
- Linux 控制台
shell shell命令分为两种:分别是内部命令和外部命令. 内部命令:在安装的时候嵌入系统内核. 外部命令:以文件的形式存在. 可以使用type命令查看是内部命令还是外部命令. Linux中,默认 ...
- [Cracking the Coding Interview] 4.6 Successor 后继节点
Write an algorithm to find the 'next' node(i.e. in-order successor) of a given node in a binary sear ...
- SapScript
* [OPEN_FORM] SAPscript: フォーム印刷の開始 * [START_FORM] SAPscript: 書式を開始 * [WRITE_FORM] SAPscript: 書式ウィンドウ ...
- VGA 时序标准
VGA 显示器扫描方式从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时,用行同步信号进行同步:当扫描完所有的行 ...
- 图片验证码给AI使用
为了破解图形验证码,AI需要大量的图片数据.为了简单获取大量的图形来喂给Ai模型训练,索性自己写一把.代码来一发.. import java.awt.Color; import java.awt. ...
- 雷哥带你走进Javascript
javascript复习笔记--------------------------------------------1.概念2.面向对象思想3.作用认识4.引入方式5.执行顺序 变量 1)声明方式 x ...