你猜呀c++
你猜呀算法
你猜呀安全
你接着猜呀spa
设最少存活人数为MIN 最多存货人数为MAX
来看张图:指针
首先咱们先来统计一下每一个点的入度,若是一个点的入度为0,则自始至终这我的都不可能被杀(没人想杀小姐姐),就像图里的1和4,因此这我的想杀的人必定会死(震惊) 也就是图中的2code
每一个人都会有想杀的人(咱也不知道为啥会想杀本身),一我的若是入度不为0 ,他想杀的人就不必定会死(为了保护你想杀的小姐姐 先把你干掉)
这样的点的目标就像3,可能会死掉(若是拯救小姐姐的人来晚了,小姐姐就被大魔王煮着吃了)
咱们能够发现:blog
若是一个点入度为0(绿框) 那么这个点必定会活下来 :MIN++ MAX++队列
最小存活:让一定会死的人2先把本身要杀的人3杀掉(undie标记3)(在勇士救出小姐姐以前吃了她)则MIN就不能加1了get
最大存活:先把一定会死的人杀死防止他去杀他要杀的人(勇士在魔王吃掉小姐姐以前干掉大魔王),那么最大存活就会加1了(就像例图中3被解救了)
But 对小姐姐图谋不轨的人远不止一个呢? 所以咱们不能直接断定小姐姐是能够存活的,可是咱们能够将小姐姐的入度--
若是入度成功变成了0。 恭喜你,小姐姐得救了(虽然不能和你幸福地生活在一块儿),咱们就能够将这个点入队了(队列维护入度为0的点,表示安全的点)it
可是若是这个点的入度并无变成0 则这个点必定也会构成一个环或者链 ,关于链显然隔一我的打一我的能够存活最多的人(n/2),存活最少的人就是只活一个(很简单,本身推)
若是环上有undie标记的人,可让这我的最后死,而后在这个环死的只剩他的时候,BOOM 干掉他
固然还有一种状况就是直接的无任何undie标记的环 , 同上
1.最小存活: +1
2.最大存活: +n/2
具体的细节去看注释吧
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+5; int n,Max,Min,q[maxn],aim[maxn],rd[maxn]; bool die[maxn],undie[maxn]; int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&aim[i]); rd[aim[i]]++; } for(int i=1;i<=n;++i) if(rd[i]==0){//入度为0的点进队 Min++;//最小存活++ q[++Max]=i;//最大存活++ } int head=1;//模拟指针 while(head<=Max){ int cur=q[head];head++;//队首出队 if(die[aim[cur]]) continue;//若是队首要杀的人已经被别人杀了 die[aim[cur]]=1;//标记队首要杀的人 int live=aim[aim[cur]];//队首目标的目标可死可不死 rd[live]--;//入度-- undie[live]=1;//能够不死了 if(rd[live]==0)//若是入度变为0了 q[++Max]=live;//最大存活数++,入队 } //下面是处理环的 for(int i=1;i<=n;++i) if(rd[i] && !die[i]){//若是当前位置入度不为0 而且还没死 int len=0,flag=0;//len为环的长度 flag断定当前人是否可能会死 for(int j=i;!die[j];j=aim[j]){//遍历环 len++;//环长度++ flag|=undie[j];//当前人是否可能会死 die[j]=1;//标记为已死 防止下次i到这个位置再计算 } if(!flag && len>1) Min++;//若是当前点不可能会死 并且环长度>1(不是自环) ,最小存活数++ Max+=len/2;//最大存活数加上环长度的一半 } printf("%d %d",n-Max,n-Min);//要输出最小死亡数和最多死亡数 return 0; }
感谢观看 点个关注>:<