日常训练 20170602 Book

来源:互联网 发布:js转换为数字 number 编辑:程序博客网 时间:2024/05/08 11:25

题意:小Z曾经是集邮部的成员,集邮部经常举办换邮票活动。活动中,如果两个人互相喜欢对方的邮票,那么这两个人就可以彼此交换自己的邮票。但在这个规则下,小Z没有换到自己喜欢的邮票。小Z觉得这是规则不完善导致的,于是小Z决定制定一个新的交换规则:每次可以选择任意多个人排成一个圆圈,如果每个人都喜欢他前边的人当前拥有的那枚邮票,就可以让每个人都拿走自己前边的人的邮票,并把自己的邮票给后边的人。在活动中可以进行任意多次这样的交换,并且一个人也可以多次参与这样的交换。
现在小 Z 知道了参加活动的人数,以及每个人喜欢哪些邮票,他想知道这次能不能让每个人都拿到一枚自己喜欢的邮票。你能帮他解决这个问题吗?
n 个人, m 组喜欢关系,2n10000,0m20000,保证二元组 (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[N], h[N], q[N];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;}