Gym101612H Hidden Supervisors
题目链接:https://vjudge.net/problem/Gym-101612H
知识点: 贪心
解题思路:
我们称除了以 \(1\) 号结点为根的树以外的树为 “其他树”。
对于每一棵树,先自底向上贪心地组队,记录下每一棵其他树没有组队的结点数及根结点是否有组队,然后对其他树进行排序(排序优先法则请参考 \(cmp()\) 函数)。
对于根结点已经有组队的树,我们直接让根结点连接 \(1\) 号结点即可;对于根结点没有组队的树,我们可以让根结点连现有的树里面没有组队的结点(如果现有的树里面的结点都已经有组队了,则直接连接到 \(1\) 号结点)。这部分我选择用一个 \(queue\) 来维护现有的树中没有组队的结点。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5+5; 4 5 struct Node{ 6 int ID; 7 bool HeadHave; 8 int NoHave; 9 }; 10 vector<int> to[maxn]; 11 bool rot[maxn],have[maxn]; 12 vector<Node> head; 13 queue<int> notn; 14 15 void dfs(int s){ 16 if(to[s].empty()) 17 return; 18 for(int i=0;i<to[s].size();i++){ 19 dfs(to[s][i]); 20 if(!have[to[s][i]]&&!have[s]) 21 have[s]=have[to[s][i]]=true; 22 } 23 } 24 void dfs1(int s){ 25 if(!have[s]) notn.push(s); 26 for(int i=0;i<to[s].size();i++){ 27 dfs1(to[s][i]); 28 } 29 } 30 bool cmp(const Node &a,const Node &b){ 31 if(a.HeadHave&&!b.HeadHave) return true; 32 else if(!a.HeadHave&&b.HeadHave) return false; 33 else{ 34 if(a.NoHave>b.NoHave) return true; 35 else return false; 36 } 37 } 38 int dfs2(int s){ 39 int ret=0; 40 if(!have[s]) ret++; 41 for(int i=0;i<to[s].size();i++) 42 ret+=dfs2(to[s][i]); 43 return ret; 44 } 45 46 int ans[maxn]; 47 int main(){ 48 freopen("hidden.in","r",stdin); 49 freopen("hidden.out","w",stdout); 50 int n; 51 scanf("%d",&n); 52 memset(rot,true,sizeof(rot)); 53 for(int i=1;i<n;i++){ 54 int x; 55 scanf("%d",&x); 56 if(x){ 57 to[x].push_back(i+1); 58 ans[i+1]=x; 59 rot[i+1]=false; 60 } 61 } 62 Node tmp; 63 for(int i=1;i<=n;i++){ 64 if(rot[i]){ 65 dfs(i); 66 if(i!=1){ 67 tmp.HeadHave=have[i]; 68 tmp.ID=i; 69 tmp.NoHave=dfs2(i); 70 head.push_back(tmp); 71 } 72 } 73 } 74 sort(head.begin(),head.end(),cmp); 75 76 dfs1(1); 77 for(int i=0;i<head.size();i++){ 78 int id=head[i].ID; 79 if(have[id]){ 80 ans[id]=1; 81 dfs1(id); 82 } else{ 83 if(notn.size()){ 84 int x=notn.front(); 85 notn.pop(); 86 have[x]=have[id]=true; 87 ans[id]=x; 88 dfs1(id); 89 } else{ 90 ans[id]=1; 91 dfs1(id); 92 } 93 } 94 } 95 int has=0; 96 for(int i=1;i<=n;i++){ 97 if(have[i]) has++; 98 } 99 printf("%d\n",has/2); 100 for(int i=2;i<=n;i++){ 101 if(i!=2) printf(" "); 102 printf("%d",ans[i]); 103 } 104 printf("\n"); 105 106 return 0; 107 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”