[USACO20OPEN]Cereal

做题时间:2021.03.01

\(【题目描述】\)

\(N(N \leq 10^5)\)头牛,每\(i\)头牛有一个最喜欢的麦片\(x_i\)以及第二喜欢的麦片\(y_i\),并有\(M(M \leq 10^5)\)种麦片,每一种只有一箱。牛按照编号从\(1\rightarrow n\)顺序拿走麦片,每一头牛首先拿自己最喜欢的麦片,如果没有了则拿走第二喜欢的麦片。

问如果去掉前\(i\)头牛,那么有几头牛会至少拿到一箱麦片。

\(【输入样例】\)

4 2
1 2
1 2
1 2
1 2

\(【输出样例】\)

2
2
2
1

\(【考点】\)

模拟。

\(【做法】\)

如果枚举那么复杂度为\(O(N^2)\),考虑反向枚举。

可以参考类似于匈牙利算法的做法,将牛作为图的\(A\)集合,麦片作为图的\(B\)集合,那么这道题目就可以当成二分图最大匹配做。

\(n\rightarrow 1\)枚举每一头奶牛,如果当前奶牛第一喜欢的麦片没有拿走,那么标记一下,答案+1,如果拿走麦片的奶牛编号比当前奶牛大,说明它在原先排队是排在当前奶牛后面的,因此这个麦片应当由当前奶牛拿走,另外一头奶牛就另寻其他麦片....... 第二喜欢的也是类似的操作。直到没有可拿的麦片就直接退出。

\(【代码】\)

#include<cstdio>
#include<iomanip>

using namespace std;
const int N=1e5+50;
int a[N],b[N];
int cy[N];
int n,m,ans[N],cnt;

void Path(int x)
{
	if(!cy[a[x]]){//奶牛x最喜欢的麦片没有被拿
		cy[a[x]]=x;cnt++;
		return ;
	}
	if(cy[a[x]]>x){//拿走奶牛x的奶牛的编号比奶牛x要大
		int tmp=cy[a[x]];
		cy[a[x]]=x;
		Path(tmp);
		return ;
	}
  
	if(!cy[b[x]]){//同上
		cy[b[x]]=x;cnt++;
		return ;
	}	
	if(cy[b[x]]>x){
		int tmp=cy[b[x]];
		cy[b[x]]=x;
		Path(tmp);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
	for(int i=n;i>=1;i--){
		Path(i);
		ans[i]=cnt;
	}
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2021-03-01 14:01  lxzy  阅读(81)  评论(0)    收藏  举报