[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;
}

浙公网安备 33010602011771号