[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\) 的排列。如果有多个符合要求的排列,输出任意一个。
样例输入
8 10
2 1
3 4
2 3
6 5
7 8
6 7
7 5
5 8
样例输出
1
1
3
2
8
4
6
5
7
二分图板子了快,类似 [ZJOI2009] 假期的宿舍,印象深刻,告诉我们可以通过简单的约束条件然后做二分图最大匹配,但复杂度\(O(NM)\) 感觉非常假,能过实属侥幸,数据水了。
当当前牛的条件都能满足时,满足方案一,返回。
若一已经被选择,尝试选择一,未果选择方案二,返回。
二分图的典型思路。难点在于第二问,如何记录方案,我们可以得知完成最大匹配的图有一个很强的性质,它可以是一张 \(DAG\) 图!完毕,拓扑排序可以解决。但是递归也行啊~
Code.
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,m,ma[N],a[N],b[N],st[N];
bool dfs(int u,int s)
{
if(st[u]==s) return 0;
st[u]=s;
if(!ma[a[u]] || dfs(ma[a[u]],s)) {ma[a[u]]=u,ma[u]=a[u];return 1;}
else if(!ma[b[u]] || dfs(ma[b[u]],s)) {ma[b[u]]=u,ma[u]=b[u];return 1;}
return 0;
}
void cou(int u)
{
if(st[u]) return;
st[u]=1;
if(!ma[u]) cou(ma[a[u]]),cou(ma[b[u]]);
else if(ma[u]==b[u]) cou(ma[a[u]]);
printf("%d\n",u);
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x,y;scanf("%d%d",&x,&y);
a[i]=x+n,b[i]=y+n;
}
for(int i=1;i<=n;i++) dfs(i,i);
int res=0;
for(int i=1;i<=n;i++) if(!ma[i]) res++;
printf("%d\n",res);
memset(st,0,sizeof st);
for(int i=1;i<=n;i++) if(!st[i]) cou(i);
return 0;
}
标签:le,ma,int,题解,return,Cereal,麦片,USACO22JAN,奶牛 来源: https://www.cnblogs.com/EastPorridge/p/16387371.html