• [NOIP2015] 信息传递


    嘟嘟嘟

    题面很清楚,就是让求最小环。

    有两种做法:

    F1:用带权并查集。将每一条边连接的两个点所在集合合并,如果已经在一个集合,说明形成了环,用dis[x] + dis[y] + 1更新ans。因为图中的边是有向的,所以并查集也必须又向,对于边(x->y),可以规定x所在集合向y和并,那么同时dis[x] = dis[y] + 1。

    F2:拓扑排序,先删去所有入度为0的点,因为这些点肯定不在环中。然后把这些点连接着的点的入度-1,继续删去所有入度为0的点。最后的图一定是一个只有简单环且不连通的图,因为题中说每一个点出度为1。对于每一个环,dfs求大小即可。

    这里给出F1的代码。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e5 + 5;
    21 inline ll read()
    22 {
    23   ll ans = 0;
    24   char ch = getchar(), last = ' ';
    25   while(!isdigit(ch)) last = ch, ch = getchar();
    26   while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    27   if(last == '-') ans = -ans;
    28   return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32   if(x < 0) x = -x, putchar('-');
    33   if(x >= 10) write(x / 10);
    34   putchar(x % 10 + '0');
    35 }
    36 
    37 int n, ans = INF;
    38 
    39 int p[maxn], dis[maxn];
    40 void init()
    41 {
    42   for(int i = 1; i <= n; ++i) p[i] = i;
    43 }
    44 int Find(int x)
    45 {
    46   if(x != p[x])
    47     {
    48       int las = p[x];
    49       p[x] = Find(p[x]);
    50       dis[x] += dis[las];
    51     }
    52   return p[x];
    53 }
    54 void merge(int x, int y)
    55 {
    56   int px = Find(x), py = Find(y);
    57   if(px != py) p[px] = py, dis[x] = dis[y] + 1;
    58   else ans = min(ans, dis[x] + dis[y] + 1);
    59 }
    60 
    61 int main()
    62 {
    63   n = read();
    64   init();
    65   for(int i = 1; i <= n; ++i)
    66     {
    67       int x = read();
    68       merge(i, x);
    69     }
    70   write(ans), enter;
    71   return 0;
    72 }
    View Code
  • 相关阅读:
    信号与系统04 离散时间傅里叶变换
    什么是吉布斯现象
    部分分式展开
    常见的傅里叶变换对
    微分运算的时域扩展
    动态库和静态库的制作与使用 【转载】原文链接https://www.cnblogs.com/WindSun/p/11287927.html
    派生访问说明符
    自定义异常类
    C++虚函数
    Linux知识点
  • 原文地址:https://www.cnblogs.com/mrclr/p/9876047.html
Copyright © 2020-2023  润新知