P2661 [NOIP2015 提高组] 信息传递 提交 92.72k 通过 32.68k 时间限制 1.00s 内存限制 125.00MB

 

>>>

题意很清楚,求图中最小的环。

如果一个人的入度为0,则肯定不可能成环,那么把这个人和他连出的边删去(即标记这个人并将他下一个人的入度减 1),

如果下一个人的入度为0则将他也删去……最后把所有入度为0的人都删去了,剩下的都是环。

每个人的出度为1,所以每个人只能在一个环中,每条边只能在一个环中,也就是说每个环都是分开的,

然后进行一遍 dfs,找出最小的环。

>>>关系看成一个有向图。对于任意一个节点进入,因为每个点的出度均为1,所以最多只能构成三种情况:1、一条链;2、一个环链;3、一条链连接着一个环链。

>>>在每次加入时查看是否有环 若无则连接 否则 维护答案  环从任一点进入都可以

:::find(x)      基操 cmp 按部就班

:::有环时不要 连接 or 死循环

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
int n,t[200050],d[200050],ans=1000000000,r[200050];
void read(int& x){
    x=0;
    int y=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') y=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x=x*y;
}
void dfs(int ti,int s,int l){
    if (ti==s&&l){                                //如果回到开始说明连成了环 
        ans=min(ans,l);
        return;
    }
    if (!d[t[ti]]) {
        d[t[ti]]=1;                                //标记 
        dfs(t[ti],s,l+1);
    }
}
void rmove(int ti){                                //删除ti 
    d[ti]=-1;                                    //标记 
    r[t[ti]]--;                                    //ti的下一个人的入度减一 
    if (!r[t[ti]]&&d[t[ti]]!=-1) rmove(t[ti]);
}
int main(){
    //freopen("ferry.in","r",stdin);
    //freopen("message.out","w",stdout);
    memset(d,0,sizeof(d));
    memset(r,0,sizeof(r));                        //r[i]为第 i 个人的入度 
    int i;
    read(n);
    for (i=1;i<=n;i++){
        read(t[i]);
        r[t[i]]++;
    }
    for (i=1;i<=n;i++){
        if (!r[i]&&d[i]!=-1) rmove(i);            //如果 i 的入度为 0 且还未被删除,则删除i 
    }
    for (i=1;i<=n;i++){
        if (!d[i]){                                //如果i还未搜过且未被删除,则从i开始搜索 
            //cout<<i<<' ';
            dfs(i,i,0);
        }
    }
    //cout<<endl;
    printf("%d",ans);
    return 0;
}
/*#include <iostream>
#include <cstdio>
using namespace std;
const int N = 200010;
int n, fa[N], ans = 0x3f3f3f3f;
int get (int x, int &cnt) { //cnt记录环的长度 
    cnt ++;
    if (fa[x] == x) return x;
    else return get(fa[x], cnt);
}
// cmp with return fa[x]==x? x: fa[x]=find(fa[x]) //->缩短查询 更改 fa 信息
int main () {
    //因为 rd==1 -> fa -> 唯一->从不同出发
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++)
        fa[i] = i;
    for (int i = 1; i <= n; i ++) {
        int cnt = 0, f;
        scanf("%d", &f);
        if (get(f, cnt) == i) {
            ans = min(ans, cnt); //维护最小的环 
        }else
            fa[i] = f;
    }
    printf("%d", ans);
    return 0;
}*/
View Code

 

 
posted @ 2023-08-11 09:20  JMXZ  阅读(85)  评论(0)    收藏  举报