zoukankan      html  css  js  c++  java
  • YYHS-NOIP2017Training0928-ZCC loves Isaac

    题目描述

    【背景】
    ZCC又在打Isaac。这次他打通了宝箱关进入了表箱关。
    【题目描述】
    表箱关有一个房间非常可怕,它由n个变异天启组成。
    每个天启都会在进入房间后吐出绿弹并炸向某一个位置且范围内只有一个天启。若该位置的天启已经死亡则没有事情发生,否则该位置的天启会死亡。每个天启只能且必须吐一次绿弹(除非在它吐弹以前他就挂了)。
    绿弹的飞行速度很快,在某个绿弹落地之前不会有新的绿弹被吐出。
    虽然房间的天启位置和吐弹位置固定,但是吐弹顺序是随机的,所以ZCC不能很好地制定策略。
    现在ZCC想知道,最少和最多有几个天启被干掉。

    输入

    第一行n表示天启个数。
    第二行n个数ai表示i号天启的目标是ai。
    注意:行末有一个空格。

    输出

    一行两个数表示最少和最多有几个天启被干掉。

    样例输入

    8 2 3 2 2 6 7 8 5

    样例输出

    3 5

    提示

     
     
     
     
     
     
     
     

    【样例解释】



    【数据范围】


    测试点编号

    n的范围

    其他

    测试点编号

    n的范围

    其他

    1

    =10

    随机生成

    6

    =10000

    处于一个联通块

    2

    =100

    随机生成

    7

    =100000

    所有天启都能被炸到

    3

    =1000

    随机生成

    8

    =100000


    4

    =1000

    随机生成

    9

    =1000000

    处于一个联通块

    5

    =10000

    随机生成

    10

    =1000000

    题解

    这道题刚开始弄了我很久,后来发现每个点只会向后连一条边,这样就少了很多种特殊情况

    这道题要我们求最少和最多被干掉的天启数量

    我们把图的情况想象成  单独一个环和其他的情况

    求最少的数量

    我们对于单独的环最少一定是干掉  (环的长度+1)/2  个天启

    而对于其他的情况 我们就从入度为0的点开始往后找,把这些点标记掉,再找入度为0的点,这样继续,在判断的时候把干掉的加起来即可

    求最大的数量

    单独的环最后一定是只剩下一个(自环除外),自环就要特判一下

    其他情况就只有入度为0的点存活,其他都会被干掉

    怎么求单独的环呢?这个问题确实弄了我很久

    其实我们可以先把入度为0的点向后找,边找边标记,一直找到找不了为止,这样剩下来的点就是构成环的点了

     1 #include<bits/stdc++.h>
     2 #define N 1000005
     3 using namespace std;
     4 int n,cnt,Max,Min,k,u,v;
     5 int a[N],in[N],s[N],flag[N];
     6 int calc(int u){
     7     flag[u]=1;
     8     int sum=1,v=u;
     9     while (!flag[a[v]]){
    10         flag[a[v]]=1;
    11         sum++;
    12         v=a[v];
    13     }
    14     if (sum==1) sum=2;
    15     return sum;
    16 }
    17 int main(){
    18     scanf("%d",&n);
    19     for (int i=1;i<=n;i++){
    20         scanf("%d",&a[i]);
    21         in[a[i]]++;
    22     }
    23     for (int i=1;i<=n;i++)
    24         if (!in[i]) s[++cnt]=i,flag[i]=true;
    25     int num=1;
    26     while (num<=cnt){
    27         k=s[num];
    28         u=a[k];
    29         if (!flag[u]){
    30             Min++; flag[u]=true;
    31             v=a[u]; 
    32             in[v]--;
    33             if (!in[v]){
    34                 s[++cnt]=v;
    35                 flag[v]=true;
    36             }
    37         }
    38         num++;
    39     }
    40     for (int i=1;i<=n;i++)
    41         if (!flag[i]) Min+=(calc(i)+1)/2;
    42     memset(flag,0,sizeof(flag));
    43     for (int i=1;i<=n;i++)
    44         in[a[i]]++;
    45     cnt=0;
    46     for (int i=1;i<=n;i++)
    47         if (!in[i]) s[++cnt]=i,flag[i]=true;
    48     num=1;
    49     while (num<=cnt){
    50         k=s[num];
    51         u=a[k];
    52         if (!flag[u]){
    53             Max++; flag[u]=true;
    54             s[++cnt]=u;
    55         }
    56         num++;
    57     }
    58     for (int i=1;i<=n;i++)
    59         if (!flag[i]) Max+=calc(i)-1;
    60     printf("%d %d
    ",Min,Max);
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    持续集成 自动化构建、测试、部署您的Coding代码
    MySQL主从 常见的错误及解决方案
    老王带你走过 Kafka 入门教程
    Spring Cloud Eureka 常用配置及说明
    关于智慧大数据中心平台建设思路
    工作经验是积累总结出来的
    程序员晋级CTO之路的8大准则
    Spring Cloud Feign 使用方法与性能优化
    Elasticsearch(ES)API 增删查改常用操作
    ELK 日志采集 实战教程
  • 原文地址:https://www.cnblogs.com/zhuchenrui/p/7611060.html
Copyright © 2011-2022 走看看