图论——拓扑排序

Wikioi 3972 妖精大作战

题目描述 Description

有N 个妖精 ,现在每一只妖精都已经把自己所有的弹幕瞄准了一只妖精(有可能是自己)。 

 

这些妖精的能力值都非常高,所以一旦将弹幕发射出去,瞄准的妖精必死无疑。 

 

为了使问题变得更有趣一些,⑨打算让这些妖精按照某个顺序来发射弹幕。一旦某个妖精已经被打死了,那么他将退出战斗。 

 

可以预见到,按照不同的顺序,最后死亡的妖精数量是不一样的。 

 

⑨想知道,死亡的妖精数量的最大值和最小值。分别是多少 

 

输入描述 Input Description

第一行一个整数N 

 

接下来N 行每行一个整数,第i 行的数值表示第i 只妖精瞄准的妖精是谁 ,保证这个整数在 [1, n]范围内。 

 

输出描述 Output Description

一行两个整数,死亡的妖精数量的最大值和最小值。 

样例输入 Sample Input

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\n", getmin(), getmax());
68 }
View Code

②自己写的

  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 }
View Code

 

 

 

 

posted @ 2015-10-02 15:32  ACforever  阅读(180)  评论(0编辑  收藏  举报