题解:P1543 [POI2004] SZP
思路
首先,这个题跟班花 没有关系。因为它最后建出来是一个有向图且题目与前缀有关,所以可以考虑拓扑排序。
至于求最大,贪心即可。
贪心部分
具体解释
显然的监视该人数量为 的人不能选。于是监视该人数量为 的人的监视的人就要选(一会再解释为什么)。
那么,对于每一个人,如果他被选了,监视他监视的人的数量就会减 (显而易见,因为他抱语文作业去了)。
如果没有人监视他监视的人了,他监视的人就不能去抱语文作业了。
正确性证明
如果我们在可以选择这个点的情况下没选这个人,那么下一个可选的点就是这个人监视的人。
按理来说,去掉这个人剩下的人少,而且去掉这个人也只有最多一个人可以被选,所以选上这个人一定是不劣的。
拓扑排序部分
显然题目没有保证是一个 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;
}
时间复杂度 。

浙公网安备 33010602011771号