2015Day1T2信息传递

3 篇文章 0 订阅
2 篇文章 0 订阅

这里写图片描述
bfs和dfs

//求最小环 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,u,y,cnt,mn=0x3fffffff,c,t,p;
int head[200005],col[200005],st[200005];
int bc[200005],b[200005],cn[200005];
//col每个连通块的颜色,st记录每个连通块
//b是否已经记录过,如果是,表示已经构成环了
//cn记录队列的编号,与环的第一个点相减表示该环的个数 
struct Data{
    int to,nxt;
};
Data edge[400005]; 
void add(int u,int v)
{
    cnt++;
    edge[cnt].to=v;//edge[2].nxt
    edge[cnt].nxt=head[u];
    head[u]=cnt;
} 
int dfs(int u,int c)
{
    for(int i=head[u];i>0;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(col[v]==0)
        {
            col[v]=c;
            dfs(v,c);
        }
    }
}
int dfs2(int u)
{
    int v=bc[u];//u的后继 
    p++;
    if(b[v]==1)
        return p-cn[v]; 
    cn[v]=p;
    b[v]=1;
    dfs2(v);
}
int main()
{
    scanf("%d",&n);
    for(int x=1;x<=n;x++)
    {
        scanf("%d",&y);
        add(x,y); 
        add(y,x);//设置成无向的 
        bc[x]=y;
    }
//  for(int i=1;i<=n;i++)
//  {
//      for(int j=hd[i];j>0;j=eg[j].nxt)
//          cout<<i<<","<<eg[j].to<<endl;
//  }
    for(int i=1;i<=n;i++)
    {
        if(col[i]==0)
        {
            c++;
            col[i]=c;
            st[++t]=i;//记录一共几个连通块 
            dfs(i,c);//将能设涉及到的都涉及 
        }
    }
//  for(int i=1;i<=t;i++)
//      cout<<i<<","<<st[i]<<endl;
    for(int i=1;i<=t;i++)
    {
        memset(cn,0,sizeof cn);
        b[st[i]]=1;p=0;
        int tmp=dfs2(st[i]);
        if(tmp<mn)
            mn=tmp;
    } 
    printf("%d\n",mn);
}
/*
9
2 4 2 3 1 7 8 6 6

output:
3 3
*/

并查集

//求最小环 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,u,y,cnt,mn=0x3fffffff,c,t,p;
int fa[200005],st[200005],jud[200005];
int bc[200005],b[200005],cn[200005];
//col每个连通块的颜色,st记录每个连通块
//b是否已经记录过,如果是,表示已经构成环了
//cn记录队列的编号,与环的第一个点相减表示该环的个数 
int find(int x)
{
    if(x==fa[x]) return x;
    find(fa[x]);
}
void uni(int p,int q)
{
    fa[q]=p;
}
int dfs2(int u)
{
    int v=bc[u];//u的后继 
    p++;
    if(b[v]==1)
        return p-cn[v]; 
    cn[v]=p;
    b[v]=1;
    dfs2(v);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        fa[i]=i;//每个点的父节点是自己 
    int g,h;
    for(int x=1;x<=n;x++)
    {
        scanf("%d",&y);
        bc[x]=y;
        g=find(x),h=find(y);
        if(g!=h)
            uni(g,h);//把两个父亲fa[h]=g进行合并 
    }
    for(int i=1;i<=n;i++)
    {
        int f=find(i);
        if(jud[f]==0) jud[f]=1,st[++t]=f;   
    }
//  for(int i=1;i<=t;i++)
//      cout<<i<<","<<st[i]<<endl;
    for(int i=1;i<=t;i++)
    {
        memset(cn,0,sizeof cn);
        b[st[i]]=1;p=0;
        int tmp=dfs2(st[i]);
        if(tmp<mn)
            mn=tmp;
    } 
    printf("%d\n",mn);
}
/*
9
2 4 2 3 1 7 8 6 6
*/

并查集-路径压缩

//求最小环 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,u,y,cnt,mn=0x3fffffff,c,t,p;
int fa[200005],st[200005],jud[200005];
int bc[200005],b[200005],cn[200005];
//col每个连通块的颜色,st记录每个连通块
//b是否已经记录过,如果是,表示已经构成环了
//cn记录队列的编号,与环的第一个点相减表示该环的个数 
int find(int x)
{
    if(x!=fa[x]) fa[x]=find(fa[x]);
    else return x;
}
void uni(int p,int q)
{
    fa[q]=p;
}
int dfs2(int u)
{
    int v=bc[u];//u的后继 
    p++;
    if(b[v]==1)
        return p-cn[v]; 
    cn[v]=p;
    b[v]=1;
    dfs2(v);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        fa[i]=i;//每个点的父节点是自己 
    int g,h;
    for(int x=1;x<=n;x++)
    {
        scanf("%d",&y);
        bc[x]=y;
        g=find(x),h=find(y);
        if(g!=h)
            uni(g,h);//把两个父亲fa[h]=g进行合并 
    }
//  for(int i=1;i<=n;i++)
//      cout<<i<<","<<fa[i]<<endl;//并不是所有点的fa[]都更新了,只是在find过程中路径上的点被更新了 

    for(int i=1;i<=n;i++)
    {
        int f=find(i);
        if(jud[f]==0) jud[f]=1,st[++t]=f;   
    }
    for(int i=1;i<=t;i++)
        cout<<i<<","<<st[i]<<endl;
    for(int i=1;i<=t;i++)
    {
        memset(cn,0,sizeof cn);
        b[st[i]]=1;p=0;
        int tmp=dfs2(st[i]);
        if(tmp<mn)
            mn=tmp;
    } 
    printf("%d\n",mn);
}
/*
9
2 4 2 3 1 7 8 6 6
*/

tarjan

//求最小环 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,x,y,tp,tim,mn;
int ans=0x3fffffff; 
int dfn[200005],low[200005],insk[200005],bc[200005],stk[200005];
//st记录每个连通块
//b是否已经记录过,如果是,表示已经构成环了
//cn记录队列的编号,与环的第一个点相减表示该环的个数
void tarjan(int u)
{
    dfn[u]=low[u]=++tim;
    insk[u]=1;
    stk[++tp]=u;
    int v=bc[u];
    if(!dfn[v])
    {
        tarjan(v);
        low[u]=min(low[u],low[v]);
    }
    else if(insk[v]==1)
    {
        low[u]=min(low[u],low[v]);
    }
    if(low[u]==dfn[u])
    {
        while(1)
        {
            mn++;
            int now=stk[tp];
            tp--;
            if(now==u) break;
        }
        if(mn>1)
            ans=min(ans,mn);
    }
} 
int main()
{
    scanf("%d",&n);
    for(int x=1;x<=n;x++)
    {
        scanf("%d",&y);
        bc[x]=y;
    } 
    for(int i=1;i<=n;i++)
    {
//        memset(dfn,0,sizeof dfn);
//        memset(low,0,sizeof low);
//        tim=0;
        mn=0;
        if(!dfn[i])
            tarjan(i);  
    } 
    cout<<ans<<endl;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值