• [POI 2004]SZP


    Description

    Byteotian 中央情报局 (BIA) 雇佣了许多特工. 他们每个人的工作就是监视另一名特工.
    Byteasar 国王需要进行一次秘密行动,所以他要挑选尽量多的信得过的特工. 但是这项任务是如此的机密以至于所有参加行动的特工都必须至少被另一名没有参加任务的特工所监视(就是说如果某个特工参加了行动,那么原先监视他的那些特工中至少要有一个没有参加进行动). 给出监视任务的详情,要求计算最多能有多少个特工参与其中.

    Input

    第一行只有一个整数, n – 特工的总数, 2 <= n <= 1000000. 特工从 1 编号. 接下来 n 行每行一个整数 ak 表示特工 k 将要监视特工 ak , 1 <= k <= n, 1 <= ak <= n, ak <> k.

    Output

    打印一个数,最多能有多少特工参加入这个任务.

    Sample Input

    6

    2

    3

    1

    3

    6

    5

    Sample Output

    3

    HINT

    题解

    可以用贪心$+$拓扑排序做。

    首先我们可以发现,入度为$0$的点必然不能被选,我们先将所有点标记为不选,将入度为$0$的点加入队列中。

    由贪心的思想,我们为了被选的点更多,我们要将不选的点所指向的点选上。

    证明:若点$i$确定为不选,若$ak[i]$不选也只能提供一个点被选($ak[i]$指向的点),故$ak[i]$选上不会差。

    若所有指向$i$的点均选,则$i$只能是不选。

    由于图可能不连通还可能有环。我们只需要最后剩下的环从任意处切开即可。

    由于我们在拓扑排序的过程中在环上做过标记。我们只要考虑没做过标记的一段,即有$i$标记为不选,$ak[i]$标记也为不选,显然我们要标记$ak[i]$为选。

     1 #include<map>
     2 #include<cmath>
     3 #include<ctime>
     4 #include<queue>
     5 #include<stack>
     6 #include<vector>
     7 #include<cstdio>
     8 #include<string>
     9 #include<cstdlib>
    10 #include<cstring>
    11 #include<iostream>
    12 #include<algorithm>
    13 #define LL long long
    14 #define Max(a,b) ((a)>(b) ? (a):(b))
    15 #define Min(a,b) ((a)<(b) ? (a):(b))
    16 using namespace std;
    17 const int N=1000000;
    18 
    19 int n;
    20 int ak[N+5];
    21 int in[N+5];
    22 bool choose[N+5],vis[N+5];
    23 queue<int>Q;
    24 int ans;
    25 
    26 int Read()
    27 {
    28     int sum=0;
    29     char c=getchar();
    30     while (c<'0'||c>'9') c=getchar();
    31     while (c>='0'&&c<='9') sum=sum*10+c-'0',c=getchar();
    32     return sum;
    33 }
    34 
    35 int main()
    36 {
    37     scanf("%d",&n);
    38     for (int i=1;i<=n;i++) ak[i]=Read(),in[ak[i]]++;
    39     for (int i=1;i<=n;i++) if (!in[i]) Q.push(i);
    40     while(!Q.empty())
    41     {
    42         int u=Q.front();Q.pop();
    43         vis[u]=1;
    44         if (choose[u])
    45         {
    46             in[ak[u]]--;
    47             if (!in[ak[u]]) Q.push(ak[u]);
    48         }
    49         else
    50         {
    51             if (!choose[ak[u]])
    52             {
    53                 choose[ak[u]]=1;
    54                 ans++;
    55                 Q.push(ak[u]);
    56             }
    57         }
    58     }
    59     for (int i=1;i<=n;i++) if (!vis[i])
    60     {
    61         vis[i]=1;
    62         int j=i;
    63         while (!vis[ak[j]])
    64         {
    65             if (!choose[j]&&!choose[ak[j]]) ans++,choose[ak[j]]=1;
    66             j=ak[j];vis[j]=1;
    67         }    
    68     }
    69     printf("%d
    ",ans);
    70     return 0;
    71 }
  • 相关阅读:
    图像的点运算----底层代码与Halcon库函数
    C#跨线程调用控件
    Halcon学习笔记——条形码的定位与识别
    简单实用angular.js购物车功能
    xampp与Hbuilder、phpstorm配置
    AJAX实现简单的注册页面异步请求
    querySelector系列方法相比 getElementsBy 系列方法有什么区别?
    用了那么久的函数,你知道函数是怎么调用的吗??
    JS eval()函数的一些见解
    5分钟让你掌握css3阴影、倒影、渐变小技巧!
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7423067.html
Copyright © 2020-2023  润新知