Wikioi 3972 妖精大作战
题目描述 Description
有N 个妖精 ,现在每一只妖精都已经把自己所有的弹幕瞄准了一只妖精(有可能是自己)。
这些妖精的能力值都非常高,所以一旦将弹幕发射出去,瞄准的妖精必死无疑。
为了使问题变得更有趣一些,⑨打算让这些妖精按照某个顺序来发射弹幕。一旦某个妖精已经被打死了,那么他将退出战斗。
可以预见到,按照不同的顺序,最后死亡的妖精数量是不一样的。
⑨想知道,死亡的妖精数量的最大值和最小值。分别是多少
输入描述 Input Description
第一行一个整数N
接下来N 行每行一个整数,第i 行的数值表示第i 只妖精瞄准的妖精是谁 ,保证这个整数在 [1, n]范围内。
输出描述 Output Description
一行两个整数,死亡的妖精数量的最大值和最小值。
样例输入 Sample Input
4
2 3 1 1
样例输出 Sample Output
3 2
数据范围及提示 Data Size & Hint
最大:按照2-1-4 的顺序发射弹幕。
代码:
①标程
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <algorithm> 5 #include <iostream> 6 using namespace std; 7 const int MAXN = 1500001; 8 int p[MAXN], n, into[MAXN];//into 出度 9 bool vis[MAXN], aj[MAXN], die[MAXN]; 10 struct Tqueue{//自定义队列 11 int l, r, data[MAXN]; 12 void clear() { l = 1; r = 0; } 13 bool empty() { return l > r; } 14 void push(int t) { data[++r] = t; } 15 int pop() { return data[l++]; } 16 } Q; 17 int getmin()//最少杀死数,从出度为0开始杀别的妖精 18 { 19 int ans = 0; 20 memset(vis, 0, sizeof(vis)); 21 memset(into, 0, sizeof(into)); 22 Q.clear(); 23 for (int i = 1; i <= n; i++) ++into[p[i]];//计算出度 24 for (int i = 1; i <= n; i++) if (into[i] == 0) Q.push(i), vis[i] = true;//出度为0进队列 25 while(!Q.empty()){ 26 int x = Q.pop();//队首元素 27 if (die[x]) continue; 28 x = p[x];//找到队首的攻击对象 29 if (die[x]) continue; 30 ++ans;//如果没死,die了他 31 die[x] =true; vis[x] =true; //处理后事 32 --into[p[x]]; //他的攻击对象安全一点 33 if (into[p[x]] == 0) Q.push(p[x]), vis[p[x]] = true;//如果已经安全,进队列。 34 } 35 for (int i = 1; i <= n; i++) if (!vis[i]){//处理环 36 int t = p[i], len = 1; vis[p[i]] = true; 37 while(t != i) { ++len; t = p[t]; vis[t] = true; } 38 ans += 1 + ((len - 1) >> 1);//最少的杀死数是一半 39 } 40 return ans; 41 } 42 int getmax()//求最多杀死数 43 { 44 int ans = n; 45 memset(into, 0, sizeof(into)); 46 memset(vis, 0, sizeof(vis)); 47 memset(aj, 0, sizeof(aj)); 48 Q.clear(); 49 for (int i = 1; i <= n; i++) ++into[p[i]];//入度为0,杀不死,减去 50 for (int i = 1; i <= n; i++) if (into[i] == 0) { --ans; Q.push(i); vis[i] = true; } 51 while(!Q.empty()){ 52 int x = Q.pop(); 53 --into[p[x]]; aj[p[x]] = true; 54 if (into[p[x]] == 0) { Q.push(p[x]); vis[p[x]] = true; } 55 } 56 for (int i = 1; i <= n; i++) if (!vis[i]){ 57 int t = p[i]; bool jc = !aj[i]; vis[i] = true; 58 while(t != i) { vis[t] = true; jc &= !aj[t]; t = p[t];}//处理环, 59 if (jc && (!(i == p[i]))) --ans;//一个环中只有一个活着的,减去。 60 } 61 return ans; 62 } 63 int main() 64 { 65 scanf("%d", &n); 66 for (int i = 1; i <= n; i++) scanf("%d", &p[i]); 67 printf("%d %d ", getmin(), getmax()); 68 }
②自己写的
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<map> 10 #define maxint ~0U>>1 11 #define maxn 100005 12 using namespace std; 13 int n,shot[maxn],ind[maxn],tind[maxn]; 14 void input(){ 15 cin>>n; 16 for(int i = 1;i <= n;i++){ 17 scanf("%d",&shot[i]); 18 tind[shot[i]] = ++ind[shot[i]]; 19 } 20 } 21 int bfs_max(){ 22 queue<int> overkill; 23 int ans = n,vis[maxn],circle,head; 24 memset(vis,0,sizeof(vis)); 25 for(int i = 1;i <= n;i++){ 26 if(ind[i] == 0){ 27 overkill.push(i); 28 ans--; 29 } 30 } 31 while(!overkill.empty()){ 32 int now = overkill.front(); 33 overkill.pop(); 34 vis[now] = vis[shot[now]] = 1; 35 ind[shot[now]]--; 36 if(ind[shot[now]] == 0) overkill.push(shot[now]); 37 } 38 39 for(int i = 1;i <= n;i++){ 40 if(!vis[i]){ 41 vis[i] = 1; 42 circle = 0; 43 head = i; 44 i = shot[i]; 45 while(i != head){ 46 if(vis[i]){ 47 circle = 0; 48 break; 49 } 50 vis[i] = 1; 51 circle++; 52 i = shot[i]; 53 } 54 if(circle) ans--; 55 } 56 } 57 return ans; 58 } 59 int bfs_min(){ 60 queue<int> softkill; 61 int ans = 0,vis[maxn],kill[maxn],circle,head; 62 memset(vis,0,sizeof(vis)); 63 memset(kill,0,sizeof(kill)); 64 for(int i = 1;i <= n;i++){ 65 if(tind[i] == 0){ 66 softkill.push(i); 67 vis[i] = 1; 68 } 69 } 70 while(!softkill.empty()){ 71 int now = softkill.front(); 72 softkill.pop(); 73 if(kill[now]) continue; 74 now = shot[now]; 75 if(kill[now]) continue; 76 kill[now] = vis[now] = 1; 77 tind[shot[now]]--; 78 ans++; 79 if(tind[shot[now]] == 0) softkill.push(shot[now]),vis[shot[now]] = 1; 80 } 81 for(int i = 1;i <= n;i++){ 82 if(!vis[i]){ 83 circle = 1; 84 head = i; 85 i = shot[i]; 86 vis[i] = true; 87 while(i != head){ 88 circle++; 89 i = shot[i]; 90 vis[i] = 1; 91 } 92 ans+=(circle+1)>>1; 93 } 94 } 95 return ans; 96 } 97 int main(){ 98 input(); 99 cout<<bfs_max()<<" "<<bfs_min(); 100 return 0; 101 }