其他分享
首页 > 其他分享> > [USACO22JAN] Cereal 2 S 题解

[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