题目显然可以转化为求每一条边对二分图最大独立集的贡献,二分图最大独立集\(=\)点数\(-\)最大匹配数,我们就有了\(50pts\)做法。

正解的做法是在原图上跑\(Tarjan\),最开始我想复杂了,后来才意识到,只要存在这样一个强连通分量,那么断掉分量内的任意一条边都不会破坏其连通性,即不管删掉哪个连边都一定会有新的匹配补充。只要让两个点不在同一个分量里面,而且原来是满流的(匹配可行边),那么它就是一个可用边(匹配必须边)。

#include <bits/stdc++.h>
using namespace std; const int N = 400010;
const int M = 800010;
const int INF = 0x3f3f3f3f; struct Graph {
int cnt, head[N]; struct edge {int nxt, to, f;}e[M]; Graph () {
cnt = -1;
memset (head, -1, sizeof (head));
} void add_edge (int u, int v, int f) {
e[++cnt] = (edge) {head[u], v, f}; head[u] = cnt;
} void add_len (int u, int v, int f) {
add_edge (u, v, f);
add_edge (v, u, 0);
} queue <int> q;
int cur[N], deep[N]; bool bfs (int s, int t) {
memcpy (cur, head, sizeof (head));
memset (deep, 0x3f, sizeof (deep));
deep[s] = 0; q.push (s);
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if (deep[v] == INF && e[i].f) {
deep[v] = deep[u] + 1;
q.push (v);
}
}
}
return deep[t] != INF;
} int dfs (int u, int t, int lim) {
if (u == t || !lim) {
return lim;
}
int tmp = 0, flow = 0;
for (int &i = cur[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if (deep[v] == deep[u] + 1) {
tmp = dfs (v, t, min (lim, e[i].f));
lim -= tmp;
flow += tmp;
e[i ^ 0].f -= tmp;
e[i ^ 1].f += tmp;
if (!lim) break;
}
}
return flow;
} int Dinic (int s, int t) {
int max_flow = 0;
while (bfs (s, t)) {
max_flow += dfs (s, t, INF);
}
return max_flow;
}
}G; int n, m, _ans, id[N]; struct Query {
int u, v; bool operator < (Query rhs) const {
return u == rhs.u ? v < rhs.v : u < rhs.u;
} bool operator == (Query rhs) const {
return u == rhs.u && v == rhs.v;
}
}q[N], ans[N]; int A (int x) {return n * 0 + x;}
int B (int x) {return n * 1 + x;} int read () {
int s = 0, w = 1, ch = getchar ();
while ('9' < ch || ch < '0') {
if (ch == '-') w = -1;
ch = getchar ();
}
while ('0' <= ch && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar ();
}
return s * w;
} stack <int> sta;
int dfn[N], low[N], col[N], vis[N]; void Tarjan (int u) {
sta.push (u);
vis[u] = true;
dfn[u] = low[u] = ++dfn[0];
for (int i = G.head[u]; ~i; i = G.e[i].nxt) {
int v = G.e[i].to;
if (!G.e[i].f) continue;
if (!dfn[v]) {
Tarjan (v);
low[u] = min (low[u], low[v]);
} else if (vis[v]) {
low[u] = min (low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
int tmp; ++col[0];
do {
tmp = sta.top ();
vis[tmp] = false;
col[tmp] = col[0];
sta.pop ();
}while (tmp != u);
}
} int main () {
cin >> n >> m;
int s = n * 2 + 1;
int t = n * 2 + 2;
for (int i = 1; i <= m; ++i) {
q[i].u = read ();
q[i].v = read ();
if (q[i].u > q[i].v) {
swap (q[i].u, q[i].v);
}
}
sort (q + 1, q + 1 + m);
for (int i = 1; i <= m; ++i) {
id[i] = G.cnt + 1;
G.add_len (A (q[i].u), B (q[i].v), 1);
G.add_len (A (q[i].v), B (q[i].u), 1);
}
for (int i = 1; i <= n; ++i) {
G.add_len (s, A (i), 1);
G.add_len (B (i), t, 1);
}
G.Dinic (s, t);
for (int i = 1; i <= t; ++i) {
if (!dfn[i]) {
Tarjan (i);
}
}
for (int i = 1; i <= m; ++i) {
if (col[A (q[i].u)] != col[B (q[i].v)] && !G.e[id[i]].f) {
ans[++_ans] = q[i];
}
}
cout << _ans << endl;
for (int i = 1; i <= _ans; ++i) {
printf ("%d %d\n", ans[i].u, ans[i].v);
}
}

Luogu P3731 [HAOI2017]新型城市化的更多相关文章

  1. 洛谷 P3731 [HAOI2017]新型城市化【最大流(二分图匹配)+tarjan】

    我到底怎么建的图为啥要开这么大的数组啊?! 神题神题,本来以为图论出不出什么花来了. 首先要理解'团'的概念,简单来说就是无向图的一个完全子图,相关概念详见度娘. 所以关于团一般都是NP问题,只有二分 ...

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

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

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

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

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

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

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

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

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

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

  7. [HAOI2017] 新型城市化

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

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

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

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

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

随机推荐

  1. Linux 环境 Intelij Idea 安装与快捷图标配置

    索引: 目录索引 参看代码 GitHub: intelij-idea.txt 一.Linux (DeepinOS) 环境 1.官网下载 ideaIU-.tar.gz 2.解压 .tar.gz -C ~ ...

  2. MySQL 执行计划中Extra(Using where,Using index,Using index condition,Using index,Using where)的浅析

      关于如何理解MySQL执行计划中Extra列的Using where.Using Index.Using index condition,Using index,Using where这四者的区别 ...

  3. C#中Skip和Take的用法

    Skip()和Take()方法都是IEnumerable<T> 接口的扩展方法,包括C#中的所有Collections类,如ArrayList,Queue,Stack等等,还有数组和字符串 ...

  4. C#基础第二天

    变量 声明的语法格式 数据类型 变量名; 常用数据类型 int  整数  值类型 double  小数  值类型 char  字符  引用类型 string 字符串 引用类型 decimal  金钱小 ...

  5. Boosting Static Representation Robustness for Binary Clone Search against Code Obfuscation and Compiler Optimization

    用于理解恶意软件的内部工作原理,并发现系统中的漏洞,逆向工程是一种耗费人工的却很重要的技术.汇编克隆搜索引擎是通过识别那些重复的或者已知的部件来帮助逆向工程师的工作,要想设计健壮的克隆搜索引擎是一项挑 ...

  6. 监控elssticSearch健康状态

    [4ajr@elk1 scripts]$ curl 172.30.210.175:9200/_cat/health [4ajr@elk1 scripts]$ cat check_es_healthy. ...

  7. 横线和文字一排,文字居中显示vertical-align: middle;

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  8. 从HTTL模板引擎看软件设计原则

    HTTL (Hyper-Text Template Language) 是一个高性能的开源JAVA模板引擎, 适用于动态HTML页面输出, 可替代JSP页面, 指令和Velocity相似.作者是阿里巴 ...

  9. c# pda

    1.去除标题栏 FormBorderStyle属性设置为none 2.去除任务栏 [System.Runtime.InteropServices.DllImport("coredll.dll ...

  10. 为什么开源外围包安装指导都是按照到/usr/local/目录下,/usr/local与/usr的区别

    很多应用都安装在/usr/local下面,那么,这些应用为什么选择这个目录呢?Automake工具定义了下面的一组变量: Directory variable Default value prefix ...