题解:P1543 [POI2004] SZP

思路

首先,这个题跟班花 yhb\texttt{y\red{hb}} 没有关系。因为它最后建出来是一个有向图且题目与前缀有关,所以可以考虑拓扑排序。

至于求最大,贪心即可。

贪心部分

具体解释

显然的监视该人数量为 00 的人不能选。于是监视该人数量为 00 的人的监视的人就要选(一会再解释为什么)。

那么,对于每一个人,如果他被选了,监视他监视的人的数量就会减 11(显而易见,因为他抱语文作业去了)。

如果没有人监视他监视的人了,他监视的人就不能去抱语文作业了。

正确性证明

如果我们在可以选择这个点的情况下没选这个人,那么下一个可选的点就是这个人监视的人。

按理来说,去掉这个人剩下的人少,而且去掉这个人也只有最多一个人可以被选,所以选上这个人一定是不劣的。

拓扑排序部分

显然题目没有保证是一个 DAG,而且样例也足够让我们看出它是有环的。

不过既然是环,那么从随便一个点断开都是等价的,所以就可以直接找一个环上的点断环就行了。

#include<bits/stdc++.h>
using namespace std;
struct node{
	int u,v,nxt;
}e[1000005];
int n,x[1000005];
queue<int>q;
int vis[1000005],ru[1000005],chu[1000005],ans[1000005],sum;
void bfs(){
	while(!q.empty()){
		int u=q.front();q.pop();
		vis[u]=1;
		if(ans[u]){
			ru[x[u]]--;
			if(ru[x[u]]==0)q.push(x[u]);
		}
		else{
			if(!ans[x[u]]){
				ans[x[u]]=1;
				sum++;
				q.push(x[u]); 
			}
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x[i];
		ru[x[i]]++;
		chu[i]++;
	}
	for(int i=1;i<=n;i++){
		if(ru[i]==0)q.push(i);
	}
	bfs();
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			vis[i]=1;
			int j=i;
			while(!vis[x[j]]){
				if(!ans[x[j]]&&!ans[j]){
					ans[x[j]]=1;
					sum++;
				}
				j=x[j];
				vis[j]=1;
			}
		} 
	}
	cout<<sum;
	return 0;
}

时间复杂度 O(n)\operatorname{O}(n)

posted @   Weslie_qwq  阅读(1)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示