您的位置:首页 > 理论基础 > 计算机网络

日常训练 20170602 Book

2017-06-06 16:38 260 查看
题意:小Z曾经是集邮部的成员,集邮部经常举办换邮票活动。活动中,如果两个人互相喜欢对方的邮票,那么这两个人就可以彼此交换自己的邮票。但在这个规则下,小Z没有换到自己喜欢的邮票。小Z觉得这是规则不完善导致的,于是小Z决定制定一个新的交换规则:每次可以选择任意多个人排成一个圆圈,如果每个人都喜欢他前边的人当前拥有的那枚邮票,就可以让每个人都拿走自己前边的人的邮票,并把自己的邮票给后边的人。在活动中可以进行任意多次这样的交换,并且一个人也可以多次参与这样的交换。

现在小 Z 知道了参加活动的人数,以及每个人喜欢哪些邮票,他想知道这次能不能让每个人都拿到一枚自己喜欢的邮票。你能帮他解决这个问题吗?

有 n 个人, m 组喜欢关系,2≤n≤10000,0≤m≤20000,保证二元组 (x,y) 不重复。每个测试点数据不超过10组。

不知所措,猜了一个结论,只要每个点有入度出度就判 Yes,结果被出题人发现我这样水过了数据,就加强了数据,把我卡成 30 分。题解是只要人与邮票能匹配就一定存在一种方案使得有解[完全不知道怎么证的][辣鸡猜结论][必要性解题]。结果就变成二分图最大匹配了。。。

#include<bits/stdc++.h>
const int N = 2e4 + 10;
const int M = 1e5 + 10;
const int INF = 1e9;
template <typename T> void read (T &x) {
x = 0; char c = getchar();
for (; !isdigit(c); c = getchar());
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
}
int n, m, S, T, x, y, s, first
, h
, q
;
struct edge{
int y, v, next;
}mp[M];
void ins(int x, int y) {
mp[++s] = (edge) {y,1,first[x]}; first[x] = s;
mp[++s] = (edge) {x,0,first[y]}; first[y] = s;
}
bool bfs() {
memset(h, 0, sizeof(h));
int head = 1, tail = 1;
h[q[head] = S] = 1;
for (int x=q[head]; head <= tail; x=q[++head])
for (int t=first[x]; t; t=mp[t].next)
if (mp[t].v && !h[mp[t].y])
h[mp[t].y] = h[x] + 1,
q[++tail] = mp[t].y;
return h[T] > 0;
}
int dfs(int x, int f) {
if (x == T) return f;
int used = 0, b;
for (int t=first[x]; t; t=mp[t].next)
if (h[mp[t].y] == h[x] + 1) {
b = dfs(mp[t].y, std::min(mp[t].v, f-used));
mp[t].v -= b;
mp[t^1].v += b;
used += b;
if (used == f) return used;
}
h[x] = -1;
return used;
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
memset(first, 0, sizeof(first)); s = 1;
S = 0; T = n * 2 + 1;
while (m--) read(x), read(y), ins(x, n + y);
for (int i=1; i <= n; i++) ins(S, i), ins(n + i, T);
while (bfs()) dfs(S, INF);
bool legal = 1;
for (int t=first[S]; t; t=mp[t].next)
if (mp[t].v) {legal = 0; break;}
if (legal)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络流 猜结论