一道不错的贪心题。
贪心:如果从叶向根广度操作,当一个节点的父亲节点的所有儿子全部都操作过就对它进行操作,那么如果该节点有一个儿子没有点亮(即被瞭望到,或者说被覆盖。)那么想该儿子一定所有儿子节点都已经进行过操作了(因为是广度,操作一个点的前提是它的所有儿子节点都操作过。),那么点亮该点必然只能点亮它本身和它的父亲节点,而点亮它的父亲节点则是至少点亮它本身和它的父亲节点(因为父亲节点可能还有其他节点。)。在费用相同的情况下,无论如何点亮父亲节点都是较优的决策。
#include<bits/stdc++.h>
using namespace std;
vector<int>tree[1505];
queue<int>q;
int f[1505],root,ans,a,k,point,n,output[1505];//解释:从左到右依次为父亲,根,答案,输入项*4,出度。
int light[1505];
int main(){
std::ios::sync_with_stdio(false);
cin>>n;
for(register int i=1;i<=n;i++)f[i]=-1;
if(n==1){//对单节点比较省事的特判
cout<<"1";
return 0;
}
for(register int i=1;i<=n;i++){
cin>>a>>k;
for(register int j=1;j<=k;j++){
cin>>point;
tree[a].push_back(point);
f[point]=a;
}
}
for(register int i=0;i<n;i++)if(tree[i].size()==0){q.push(i);}
for(register int i=0;i<n;i++)if(f[i]==-1)root=i;
for(register int i=0;i<n;i++)output[i]=tree[i].size();
while(!q.front()==root){
int now=q.front();
q.pop();
output[f[now]]--;
if(!light[now]){light[f[now]]=1;}//如果自己没被点亮,就点亮父亲
if(output[f[now]]==0)q.push(f[now]);//如果父亲的儿子都处理了,就等会处理父亲
}
for(register int i=0;i<n;i++)if(light[i]==1)ans++;
cout<<ans;
}