你猜呀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; }
感謝觀看 點個關注>:<