2015Day1T2信息传递

来源:互联网 发布:java 1.8 下载地址 编辑:程序博客网 时间:2024/06/06 18:05

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);}/*92 4 2 3 1 7 8 6 6output: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);}/*92 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);}/*92 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;}