P8095 [USACO22JAN] Cereal 2 S 谷物早餐

发布时间 2023-07-13 09:05:48作者: 2020fengziyang

P8095 [USACO22JAN] Cereal 2 S 谷物早餐

[P8095 USACO22JAN] Cereal 2 S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

[USACO22JAN] Cereal 2 S

题目描述

Farmer John 的奶牛们的早餐最爱当然是麦片了!事实上,奶牛们的胃口是如此之大,每头奶牛一顿饭可以吃掉整整一箱麦片。

最近农场收到了一份快递,内有 \(M\) 种不同种类的麦片(\(2\le M\le 10^5\))。不幸的是,每种麦片只有一箱!\(N\) 头奶牛(\(1\le N\le 10^5\))中的每头都有她最爱的麦片和第二喜爱的麦片。给定一些可选的麦片,奶牛会执行如下的过程:

  • 如果她最爱的麦片还在,取走并离开。

  • 否则,如果她第二喜爱的麦片还在,取走并离开。

  • 否则,她会失望地哞叫一声然后不带走一片麦片地离开。

当你最优地排列这些奶牛时,求饥饿的奶牛的最小数量。同时,求出任意一个可以达到此最小值的 \(N\) 头奶牛的排列。

输入格式

输入的第一行包含两个空格分隔的整数 \(N\)\(M\)

对于每一个 \(1\le i\le N\),第 \(i\) 行包含两个空格分隔的整数 \(f_i\)\(s_i\)\(1\le f_i,s_i\le M\),且 \(f_i\neq s_i\)),为第 \(i\) 头奶牛最喜爱和第二喜爱的麦片。

输出格式

输出饥饿的奶牛的最小数量,并输出任意一个可以达到此最小值的 \(1\ldots N\) 的排列。如果有多个符合要求的排列,输出任意一个。

样例 #1

样例输入 #1

8 10
2 1
3 4
2 3
6 5
7 8
6 7
7 5
5 8

样例输出 #1

1
1
3
2
8
4
6
5
7

提示

【样例解释】

在这个例子中,有 \(8\) 头奶牛和 \(10\) 种麦片。

注意我们对前三头奶牛独立于后五头奶牛求解,因为她们没有共同喜欢的麦片。

如果前三头奶牛按顺序 \([1,2,3]\) 进行选择,则奶牛 \(1\) 会选择麦片 \(2\),奶牛 \(2\) 会选择麦片 \(3\),奶牛 \(3\) 会饥饿。

如果前三头奶牛按顺序 \([1,3,2]\) 进行选择,则奶牛 \(1\) 会选择麦片 \(2\),奶牛 \(3\) 会选择麦片 \(3\),奶牛 \(2\) 会选择麦片 \(4\);没有奶牛会饥饿。

当然,还存在其他排列使得前三头奶牛均不饥饿。例如,如果前三头奶牛按顺序 \([3,1,2]\) 选择,则奶牛 \(3\) 会选择麦片 \(2\),奶牛 \(1\) 会选择麦片 \(1\),奶牛 \(2\) 会选择麦片 \(3\);同样,奶牛 \([1,2,3]\) 均不会饥饿。

可以证明在后五头奶牛中,至少一头会饥饿。

【数据范围】

  • \(14\) 个测试点中的 \(4\) 个测试点满足 \(N,M\le 100\)

  • \(14\) 个测试点中的 \(10\) 个测试点没有额外限制。

【说明】

本题采用自行编写的 Special Judge。如果对此有疑问或想要 hack,请私信编写者发帖

分析

二分图匹配 + 拓扑排序求答案

#include <bits/stdc++.h>
#define fu(x, y, z) for (int x = y; x <= z; x++)
using namespace std;
const int N = 1e6 + 5;
int n, m, cnt, hd[N], a[N], b[N], vis[N], flg[N], len , ct[N] , ru[N];
struct RE {
    int f, s;
} t[N];
struct node {
    int to, nt;
} e[N << 2];
void add(int x, int y) { e[++cnt].to = y, e[cnt].nt = hd[x], hd[x] = cnt , ru[y] ++; }
int dfs(int x) {
    if (!vis[t[x].f]) {
        vis[t[x].f] = 1;
        if (!b[t[x].f] || dfs (b[t[x].f])) {
            a[x] = t[x].f , b[t[x].f] = x;
            vis[t[x].f] = 0;
            return 1;
        }
    }
    if (!vis[t[x].s]) {
        vis[t[x].s] = 1;
        if (!b[t[x].s] || dfs (b[t[x].s])) {
            a[x] = t[x].s , b[t[x].s] = x;
            vis[t[x].s] = 0;
            return 1;
        }
    }
    return 0;
}
void fans(int x) {
    printf ("%d\n" , x);
    ct[x] = 1;
    for (int i = hd[x]; i; i = e[i].nt)
        fans(e[i].to);
}
void tp () {
    fu (i , 1 , n) vis[i] = 0;
    int sum = 0;
    while (sum < n) {
        fu (i , 1 , n) {
            if (vis[i]) continue;
            if (!ru[i]) {
                vis[i] = 1;
                printf ("%d\n" , i);
                sum ++;
                for (int j = hd[i] ; j ; j = e[j].nt)
                    ru[e[j].to] --;
            }
        }
    }
}
int main() {
    scanf("%d%d", &n, &m);
    fu(i, 1, n) {
        scanf("%d%d", &t[i].f, &t[i].s);
    }
    int tot = 0;
    fu(i, 1, n) {
        tot += dfs (i);
    }
    printf ("%d\n" , n - tot);
    fu (i , 1 , m)
        if (i == t[b[i]].s) 
            add (b[t[b[i]].f] , b[i]);
    tp ();
    return 0;
}