P8095 [USACO22JAN] Cereal 2 S 谷物早餐

P8095 [USACO22JAN] Cereal 2 S 谷物早餐

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

[USACO22JAN] Cereal 2 S

题目描述

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

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

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

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

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

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

输入格式

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

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

输出格式

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

样例 #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 8 8 头奶牛和 10 10 10 种麦片。

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

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

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

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

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

【数据范围】

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

  • 14 14 14 个测试点中的 10 10 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;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值