1. 程式人生 > >P2661 資訊傳遞(tarjan判最小環/拓撲思想+dfs)

P2661 資訊傳遞(tarjan判最小環/拓撲思想+dfs)

傳送門

題解:可以看出這個題是一個求圖的最小環的板題

一:先找出入度為0的點,把這些點以及這些出邊刪去,最後剩餘的跑出最小環

附上程式碼:


#include<bits/stdc++.h>

using namespace std;

const int maxn=2e5+50;

int in[maxn],book[maxn],mapp[maxn],ans,temp;

void dfs(int beginn)
{
    book[beginn]=1;
    in[mapp[beginn]]--;
    if(in[mapp[beginn]]==0){
        dfs(mapp[beginn]);
    }
}

void dfs1(int anc,int beginn)
{
    book[beginn]=1;
    temp++;
    if(mapp[beginn]==anc){
        return ;
    }else{
        dfs1(anc,mapp[beginn]);
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&mapp[i]);
        in[mapp[i]]++;
    }
    for(int i=1;i<=n;i++){
        if(in[i]==0&&!book[i]){
            dfs(i);
        }
    }
    ans=0x3f3f3f3f;
    for(int i=1;i<=n;i++){
        if(in[i]&&!book[i]){
            temp=0;
            dfs1(i,i);
            ans=min(ans,temp);
        }
    }
    printf("%d\n",ans);
    return 0;
}

二:使用tarjan直接更新出最小環(最小環至少長度為2)即可

附上程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int maxn=2e5+50;

struct edge{
    int v,next;
};
edge edges[maxn];
int head[maxn],cnt;

int dfn[maxn],low[maxn],stack[maxn],visit[maxn],tot,iindex;
int ans=0x3f3f3f3f,temp;
int n,v;

void add(int x,int y)
{
    edges[cnt].v=y;
    edges[cnt].next=head[x];
    head[x]=cnt++;
}

void tarjan(int x)
{
    dfn[x]=low[x]=++tot;
    stack[++iindex]=x;
    visit[x]=1;
    for(int i=head[x];~i;i=edges[i].next){
        if(!dfn[edges[i].v]){
            tarjan(edges[i].v);
            low[x]=min(low[x],low[edges[i].v]);
        }else if(visit[edges[i].v]){
            low[x]=min(low[x],dfn[edges[i].v]);
        }
    }
    temp=0;
    if(low[x]==dfn[x]){
        do{
            temp++;
            visit[stack[iindex]]=0;
            iindex--;
        }while(x!=stack[iindex+1]);
        if(temp>1){
            ans=min(ans,temp);
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&v);
        add(i,v);
    }
    tot=0,iindex=0;
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    printf("%d\n",ans);
    return 0;
}