原题链接

即求二分图的不可行边数量,因为不保证是完备匹配,所以需要通过网络流求出任意一组最大匹配,并建立新图判断。

建新图:对于跑完网络流的图上已经匹配的边,建立反边;对于没有匹配的边,建立正边(图只改变边的方向,别的结构不变)。

有结论:

  1. 必须边的判定条件为:\((x,y)\)的流量为\(1\),并且在残量网络上属于不同的强联通分量。
  2. 可行边的判定条件为:\((x,y)\)的流量为\(1\),或者在残量网络上属于同一个强联通分量。

所以我们在新图上跑\(tarjan\),再逐边检验即可。

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 2e4 + 10;
const int M = 2e5 + 10;
struct dd {
int x, y;
};
dd a[M];
int fi[N], di[M << 1], ne[M << 1], da[M << 1], cfi[N], cdi[M], cne[M], dfn[N], low[N], sta[N], bl[N], cu[N], de[N], q[M << 1], an[M], l = 1, tp, lc, SCC, st, ed, ti;
bool v[N];
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
inline void add_c(int x, int y)
{
cdi[++lc] = y;
cne[lc] = cfi[x];
cfi[x] = lc;
}
inline int minn(int x, int y)
{
return x < y ? x : y;
}
bool bfs()
{
int i, x, y, head = 0, tail = 1;
memset(de, 0, sizeof(de));
q[1] = st;
de[st] = 1;
while (head ^ tail)
{
x = q[++head];
for (i = fi[x]; i; i = ne[i])
if (!de[y = di[i]] && da[i] > 0)
{
de[y] = de[x] + 1;
if (!(y ^ ed))
return true;
q[++tail] = y;
}
}
return false;
}
int dfs(int x, int k)
{
int y, mi;
if (!(x ^ ed))
return k;
for (int &i = cu[x]; i; i = ne[i])
if (!(de[y = di[i]] ^ (de[x] + 1)) && da[i] > 0)
{
mi = dfs(y, minn(k, da[i]));
if (mi > 0)
{
da[i] -= mi;
da[i ^ 1] += mi;
return mi;
}
}
return 0;
}
void tarjan(int x)
{
int i, y;
dfn[x] = low[x] = ++ti;
sta[++tp] = x;
v[x] = 1;
for (i = cfi[x]; i; i = cne[i])
{
if (!dfn[y = cdi[i]])
{
tarjan(y);
low[x] = minn(low[x], low[y]);
}
else
if (v[y])
low[x] = minn(low[x], dfn[y]);
}
if (!(dfn[x] ^ low[x]))
{
SCC++;
do
{
y = sta[tp--];
bl[y] = SCC;
v[y] = 0;
} while (x ^ y);
}
}
int main()
{
int i, n, m, k, x, y, s = 0;
n = re();
m = re();
k = re();
st = n + m + 1;
ed = st + 1;
for (i = 1; i <= k; i++)
{
x = re();
y = re() + n;
a[i].x = x;
a[i].y = y;
add(x, y, 1);
add(y, x, 0);
}
for (i = 1; i <= n; i++)
{
add(st, i, 1);
add(i, st, 0);
}
for (i = 1; i <= m; i++)
{
add(i + n, ed, 1);
add(ed, i + n, 0);
}
while (bfs())
{
for (i = 1; i <= ed; i++)
cu[i] = fi[i];
while (dfs(st, 1e9) > 0);
}
for (i = 2; i <= l; i++)
if (da[i])
add_c(di[i ^ 1], di[i]);
for (i = 1; i <= ed; i++)
if (!dfn[i])
tarjan(i);
for (i = 1; i <= k;i++)
if (bl[a[i].x] ^ bl[a[i].y] && da[i << 1])
an[++s] = i;
printf("%d\n", s);
if (!s)
{
printf("\n");
return 0;
}
for (i = 1; i < s; i++)
printf("%d ", an[i]);
printf("%d", an[s]);
return 0;
}

CH#17C 舞动的夜晚的更多相关文章

  1. [Contest Hunter#17-C] 舞动的夜晚

    [题目链接] http://contest-hunter.org:83/contest/CH%20Round%20%2317/%E8%88%9E%E5%8A%A8%E7%9A%84%E5%A4%9C% ...

  2. ContestHunter#17-C 舞动的夜晚

    Description: L公司和H公司举办了一次联谊晚会.晚会上,L公司的N位员工和H公司的M位员工打算进行一场交际舞.在这些领导中,一些L公司的员工和H公司的员工之间是互相认识的,这样的认识关系一 ...

  3. CH Round #17 舞动的夜晚

    舞动的夜晚 CH Round #17 描述 L公司和H公司举办了一次联谊晚会.晚会上,L公司的N位员工和H公司的M位员工打算进行一场交际舞.在这些领导中,一些L公司的员工和H公司的员工之间是互相认识的 ...

  4. AcWing 380. 舞动的夜晚

    大型补档计划 题目链接 这题是求必须边,而不是不可行边,因为不可行边 = 必须边 + 死掉了的边(貌似lyd第三版书上还是说的不可行边)先跑最大流. 在跑完以后的残余网络上,对于一条当前匹配的边 \( ...

  5. 0x6A 网络流初步

    CH Round #17-C 这个算是一个技能点吧,不点不会,点了就没什么了.懒得写看书吧书上的1应该是0... 我又回来了太懒了不想翻书还是写写吧 必须边的判定条件:该边流量为0且两端的点在残余网络 ...

  6. Noip模拟58 2021.9.21(中秋祭&&换机房祭)

    第一次在学校过中秋节,给家里人视频电话,感觉快回家了很开心, 然后还吃了汉堡喝饮料非常爽,颓废了一会儿还换了新机房,$Linux2.0$非常dei,少爷机也非常快, 发现好像测评机又成了老爷机,这就是 ...

  7. 2021.9.21考试总结[NOIP模拟58]

    T1 lesson5! 开始以为是个无向图,直接不懂,跳去T2了. 之后有看了一眼发现可暴力,于是有了\(80pts\). 发现这个图是有拓扑序的,于是可以用拓扑排序找最长路径.先找原图内在最长路径上 ...

  8. 总结-一本通提高篇&算竞进阶记录

    当一个人看见星空,就再无法忍受黑暗 为了点亮渐渐沉寂的星空 不想就这样退役 一定不会鸽の坑 . 一本通提高篇 . 算竞进阶 . CDQ & 整体二分 . 平衡树 . LCT . 字符串 . 随 ...

  9. [考试反思]1019csp-s模拟测试80(a):天遣

    A组题,所以把榜粘全了. 第6名,被卡在刚好正中间. 我最近干什么伤天害理的事了?(例如说没有在skyh去上厕所的时候捶他) 上来看T1,非常贴心出题人直接把递推式子给你了,然后就和斐波数的递推一样了 ...

随机推荐

  1. win10虚拟桌面;一不小心按错了突然只剩下桌面,启动的程序都没了

    先说如何关闭虚拟桌面:ctrl+win+F4(万一你还没看到怎么关闭虚拟桌面,就创建并调整到虚拟桌面,会很懵的,因为你启动的所有程序全部都突然消失了,只剩下开机的桌面了): win10有个功能,虚拟桌 ...

  2. 2018面向对象程序设计(Java)第14周学习指导及要求

    2018面向对象程序设计(Java)第14周学习指导及要求(2018.11.29-2018.12.2)   学习目标 (1) 掌握GUI布局管理器用法: (2) 掌握各类Java Swing组件用途及 ...

  3. Java进阶 线程安全

    多线程编程中的三个核心概念 原子性 这一点,跟数据库事务的原子性概念差不多,即一个操作(有可能包含有多个子操作)要么全部执行(生效),要么全部都不执行(都不生效). 关于原子性,一个非常经典的例子就是 ...

  4. ChromDevTools

    [ChromDevTools] 1.如何打开DevTools. 在Chrome菜单中选择 更多工具 > 开发者工具 在页面元素上右键点击,选择 “检查” 使用 快捷键 F12 2.切换 Devi ...

  5. sed常见用法总结

    编辑文本 sed -i '1i xyz' test.txt 在第一行之前 sed -i '1a xyz' test.txt 在第一行之后插入 sed -i '1c xyz' test.txt 把第一行 ...

  6. 解题(LevenshteinInstance--Levenshtein距离)

    题目描述 Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数.许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符.编辑距离 ...

  7. day22 面向对象基础

    1.什么是面向过程 在介绍面向对象之前,要先明确面向过程 在这之前我们所写的任何代码都是面向过程的 什么是面向过程? 是一种编程思想 面对 朝向 在编写代码时,要时刻想着过程这两个字 过程指的是什么? ...

  8. streaming窗口操作

    之前一直对窗口操作不太理解.认为spark streaming本身已经是分片计算,还需要窗口操作干啥. 窗口操作最为简单易懂的场景就是,在M时间间隔计算一次N时间内的热搜.当M=N的时候,就像上述所说 ...

  9. Android开发之getX,getRawX,getWidth,getTranslationX等的区别

    转载请注明出处:http://blog.csdn.net/dmk877/article/details/51550031      好久没写博客了,最近工作确实挺忙的,刚刚结束了一个TV项目的开发,对 ...

  10. easyui中自定义下拉框的使用

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