• 【NOIP2015】信息传递


    本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P2661


    看起来是一道水题,却花费了我大量的宝贵时间。一开始我用了一种比较朴素的做法,枚举传递次数,然后模拟每个人的生日传递到了哪,时间复杂度比较玄,为O(ans*n),只得了80分。然后仔细分析一下这道题,每个人都有一个固定的传递对象,转化到图论上,就是每个点的出度均为1,然后答案要求最少玩几轮可以得知自己的生日,也就是在这样一个图中找到一个长度最小的环。这样的话,做法就不是很固定了。一种思路是,从每个结点出发,逐个遍历并做好标记,如果发现走到一个曾经走过的点,那么就发现了一个环,用他去更新答案,然后跳出(这个环一定是从开始的那个结点出发所能走到的环中最小的),对于每个被标记的点,就不用再从他出发走一遍了,因此复杂度近似O(n)。这种思路并不完善,因为图中有环,也有环上加几条链这种情况。假如我们已经走过了环,那么再走链,一旦遇到环,就会再去更新,显然会出错。怎么保证先走链呢?其实可以换种做法,而且还算是种优化,类似于拓扑排序,我们删掉入度为1的点和从他出发的边,这样就可能又得到一个入度为0的点,继续删除,最终图上就会只剩下环。而且因为每个结点出度均为1,所以每个环都是互不相干的,可以放心大胆的遍历、标记。

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 inline int get_num() {
     7     int num = 0;
     8     char c = getchar();
     9     while (c < '0' || c > '9') c = getchar();
    10     while (c >= '0' && c <= '9')
    11         num = num * 10 + c - '0', c = getchar();
    12     return num;
    13 }
    14 
    15 const int maxn = 2e5 + 5;
    16 
    17 int T[maxn], vis[maxn], d[maxn];
    18 
    19 int main() {
    20     int n = get_num(), cnt = 0, ans = 0x3f3f3f3f;
    21     for (int i = 1; i <= n; ++i)
    22         T[i] = get_num(), ++d[T[i]];
    23     for (int i = 1; i <= n; ++i)
    24         if (!d[i]) {
    25             d[i] = -1;
    26             for (int j = T[i]; ; j = T[j]) if (--d[j]) break;
    27             else d[j] = -1;
    28         }
    29     for (int i = 1; i <= n; ++i) {
    30         if (vis[i] || d[i] == -1) continue;
    31         cnt = 0;
    32         for (int j = i; ; j = T[j])
    33             if (!vis[j]) vis[j] = ++cnt;
    34             else {
    35                 ans = min(ans, cnt + 1 - vis[j]);
    36                 break;
    37             }
    38     }
    39     printf("%d", ans);
    40     return 0;
    41 }
    AC代码(删除链)

    当然,删除链只是一种方法,我们直接搜也不是不可以,但要保证,更新答案是在同一次遍历中,因此可以加一个变量,记录本次遍历最开始的时间戳。

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 inline int get_num() {
     7     int num = 0;
     8     char c = getchar();
     9     while (c < '0' || c > '9') c = getchar();
    10     while (c >= '0' && c <= '9')
    11         num = num * 10 + c - '0', c = getchar();
    12     return num;
    13 }
    14 
    15 const int maxn = 2e5 + 5;
    16 
    17 int to[maxn], vis[maxn];;
    18 
    19 int main() {
    20     int n = get_num(), dfn = 0, start, ans = 0x3f3f3f3f;
    21     for (int i = 1; i <= n; ++i) to[i] = get_num();
    22     for (int i = 1; i <= n; ++i)
    23         if (!vis[i]) {
    24             start = dfn + 1;
    25             for (int p = i; p; p = to[p]) {
    26                 ++dfn;
    27                 if (vis[p]) {
    28                     if (vis[p] >= start)
    29                         ans = min(ans, dfn - vis[p]);
    30                     break;
    31                 } else vis[p] = dfn;
    32             }
    33         }
    34     printf("%d", ans);
    35     return 0;
    36 }
    AC代码(直接遍历)
  • 相关阅读:
    怎样为flash配置Alcon调试工具
    8.9Go简介
    8.14GO之条件语句
    8.10Go之基础语法
    8.11Java之数组知识回顾
    8.13Go之常量
    8.10Go执行流、编译、特点、转义字符
    8.14Go之运算符(Operator)
    8.14Java之使用HttpClient类通过POST方式上传文件
    8.10Go之语言数据类型
  • 原文地址:https://www.cnblogs.com/Mr94Kevin/p/9521585.html
Copyright © 2020-2023  润新知