• 图论——拓扑排序


    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
    ", 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
  • 相关阅读:
    中国身份证号码验证
    防止盗链下载问题
    Microsoft .NET Pet Shop 4 架构与技术分析
    常用操作封装类
    ASP.NET 2.0页面框架的几处变化
    普通字符串与HTML相互转换的小经验
    HttpWebRequest实现读取天气预报信息
    事务回滚 c# .net代码
    CAJViewer,AdobeReader等阅读器实现金山词霸屏幕取词功能
    01背包问题动态规划详解
  • 原文地址:https://www.cnblogs.com/hyfer/p/4852288.html
Copyright © 2020-2023  润新知