【noip 2015】信息传递

去题面的传送门
QAQ这题有两种做法

Solution 1: 暴力找环

很明显题目是让找最小环,那我们就顺着找呗。一开始尝试用递归做,弄了半天也不行,不太好记录已经跑过了几个点。
其实每一个点的出度都是1,所以不用存图,直接一个数组记录每一个点连接的下一个节点是哪一个就行了。
记得还要for一遍,确定每一个点都跑过。
但是一开始这样交超时了。
后来发现,其实每次从一个点开始找环的时候,如果直接找到的下一个点是之前访问过的,直接return就好了

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=200000+10;
int n,ans,tot;
int nxt[maxn],pre[maxn],cnt[maxn];

void done(int x)
{
    int now=x,num=0;
    while(true)
    {
        num++;
        if(pre[now])
        {
            if(pre[now]==x) ans=min(ans,num-cnt[now]);
            break;
        }
        cnt[now]=num;
        if(!pre[now]) tot++;
        pre[now]=x;
        now=nxt[now];
    }
}
int main()
{
    scanf("%d",&n);
    ans=2147483647;
    for(int i=1;i<=n;++i) scanf("%d",&nxt[i]);
    for(int i=1;i<=n;++i)
    {
        if(tot==n) break;
        if(!pre[i]) done(i);
    }
    printf("%d",ans); 
    return 0;
}

Solution 2:tarjan找环

很简单,打了一遍没调就过了
直接上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;

const int maxn=200000+10;
int n,scc_cnt,Index,ans;
int nxt[maxn],scc[maxn],dfn[maxn],low[maxn];
vector<int>incom[maxn];
stack<int>s;

void tarjan(int i)
{
    dfn[i]=low[i]=++Index;
    s.push(i);
    if(!dfn[nxt[i]])
    {
        tarjan(nxt[i]);
        low[i]=min(low[i],low[nxt[i]]);
    }
    else if(!scc[nxt[i]]) low[i]=min(dfn[nxt[i]],low[i]);
    if(low[i]==dfn[i])
    {
        scc_cnt++;
        int j;
        do
        {
            j=s.top();
            s.pop();
            incom[scc_cnt].push_back(j);
            scc[j]=scc_cnt;
        }
        while(i!=j);
    }
}
int main()
{
    scanf("%d",&n);
    ans=2147483647;
    for(int i=1;i<=n;++i) scanf("%d",&nxt[i]);
    for(int i=1;i<=n;++i)
      if(!scc[i]) tarjan(i);
    for(int i=1;i<=scc_cnt;++i)
    {
        int x=incom[i].size();
        if(x>1)
          ans=min(ans,x);
    }
    printf("%d",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值