zoukankan      html  css  js  c++  java
  • 图结构练习——判断给定图是否存在合法拓扑序列(dfs算法(第一个代码),邻接矩阵(前两个代码),邻接表(第三个代码))

    图结构练习——判断给定图是否存在合法拓扑序列

    Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^

    题目描述

     给定一个有向图,判断该有向图是否存在一个合法的拓扑序列。

    输入

     输入包含多组,每组格式如下。
    第一行包含两个整数n,m,分别代表该有向图的顶点数和边数。(n<=10)
    后面m行每行两个整数a b,表示从a到b有一条有向边。
     

    输出

     若给定有向图存在合法拓扑序列,则输出YES;否则输出NO。
     

    示例输入

    1 0
    2 2
    1 2
    2 1
    

    示例输出

    YES
    NO

    网上看到有人的思路很巧妙,忍不住就稍作修改,贴了上来:http://www.cnblogs.com/luyingfeng/archive/2013/07/29/3223090.html
    第一种思路是直接判断环是否存在的思路,这种思路采用dfs算法,是非常规思路:
     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 int vis[11];
     5 int m,n,u,v;
     6 int map[11][11];
     7 int dfs(int u)//深度优先搜索遍历
     8 {
     9     vis[u]=-1;//标记-1,正在访问
    10     for(v=1; v<=m; v++)
    11     {
    12         if(map[u][v])//如果v是u的后继元素
    13         {
    14             if(vis[v]<0)//如果v元素是正在访问中的状态
    15                 return 0;//存在自环
    16             //如果存在的不是自环
    17             if(!vis[v]&&!dfs(v))//v元素还没有被访问而且v的后继元素和前面的正在访问的元素构成了回路
    18                 return 0;
    19         }
    20     }
    21     //若果u的后继结点全部没有形成自回路或者是回路
    22     vis[u]=1;//标记1,访问完了,删除此节点
    23     return 1;
    24 }
    25 int toposort()
    26 {
    27     for(u=1; u<=m; u++)
    28     {
    29         if(!vis[u])//如果u节点还没有访问
    30         {
    31             if(!dfs(u))//如果dfs的返回值是0,强制退出排序函数toposort,表明存在环
    32                 return 0;
    33         }
    34     }
    35     return 1;//如果u从1到m全部遍历完
    36 }
    37 int main()
    38 {
    39     while(~scanf("%d %d",&m,&n)&&(m+n!=0))
    40     {
    41         memset(vis,0,sizeof(vis));
    42         memset(map,0,sizeof(map));
    43         for(int i=0; i<=n-1; i++)
    44         {
    45             scanf("%d %d",&u,&v);
    46             map[u][v]=1;
    47         }
    48         if(toposort())//如果返回值是1,不存在回路,无论是自回路或者是回路
    49             printf("YES
    ");
    50         else printf("NO
    ");//如果返回值是0
    51     }
    52     return 0;
    53 }
    View Code
    常规思路,也是书上的思路,即判断是否存在入度为0的节点,若在循环未结束的时候,就找不到入度为0的节点,则必存在环
     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 int map[51][51],count[51];
     5 int flag;
     6 int u,v,vis;
     7 int main()
     8 {
     9     int m,n;
    10     while(~scanf("%d %d",&m,&n)&&(n!=0||m!=0))
    11     {
    12         memset(map,0,sizeof(map));
    13         memset(count,0,sizeof(count));//每个节点的入度初始为0;
    14         vis=0;//标记变量,用于帮助最后输出
    15         for(int i=0; i<=n-1; i++)
    16         {
    17             scanf("%d %d",&u,&v);
    18             map[u][v]=1;
    19             count[v]++;
    20         }
    21         for(int i=0; i<=m-1; i++)
    22         {
    23             int flag=0;
    24             for(u=1; u<=m; u++)
    25             {
    26                 if(count[u]==0)
    27                 {
    28                     flag=1;//只要有入度为0的点就变为1
    29                     count[u]--;//删除掉这个节点
    30                     for(v=1; v<=m; v++)//凡是与该节点有关的所有结点入度去掉1;
    31                     {
    32                         if(map[u][v])
    33                         {
    34                             count[v]--;
    35                         }
    36                     }
    37                     break;
    38                 }
    39             }
    40             if(flag==0)//如果没有入度为0的点,就代表没有拓扑序列
    41             {
    42                    vis=1;
    43                    break;
    44             }
    45         }
    46         if(vis==0)
    47         printf("YES
    ");
    48         else printf("NO
    ");
    49     }
    50     return 0;
    51 }
    View Code

    以上两种算法全部采用邻接矩阵的方法,但是采用邻接表的方法更具有一般性,这也是以上两种方法的不足之处。

     以下是用邻接表的方法:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 struct vode
     5 {
     6     int v;
     7     struct vode *next;
     8 };
     9 struct vode *f[1001];
    10 int count[1001];
    11 int stack[101],top=1;
    12 int m,n;
    13 int topsort()
    14 {
    15     int i,sum=0;
    16     int flag;
    17     while(1)
    18     {
    19         flag=0;
    20         for(i=1;i<=m;i++)
    21         {
    22             if(count[i]==0)
    23             {
    24                 stack[top++]=i;
    25                 sum++;
    26                 count[i]--;//删除i节点
    27                 struct vode *p;
    28                 for(p=f[i];p!=NULL;p=p->next)//把i节点的邻接点的入度都减1
    29                 {
    30                     int t=p->v;
    31                     count[t]--;
    32                 }
    33                 flag=1;
    34             }
    35             if(flag==1)break;//如果找到了入度是0的节点,从头开始再找入度是0的节点
    36         }
    37         if(flag==0)//循环完了之后再也找不到入度是0的节点,这时候可能会有环,也可能没有环
    38         {
    39             break;
    40         }
    41     }
    42     return sum;
    43 }
    44 int main()
    45 {
    46     while(scanf("%d%d",&m,&n)!=EOF)
    47     {
    48         int i;
    49         memset(count,0,sizeof(count));
    50         for(i=0;i<=m;i++)
    51             f[i]=NULL;
    52         for(i=1;i<=n;i++)
    53         {
    54             int u,v;
    55             scanf("%d%d",&u,&v);
    56             count[v]++;
    57             struct vode *p;
    58             p=(struct vode *)malloc(sizeof(struct vode));
    59             p->v=v;
    60             p->next=f[u];
    61             f[u]=p;
    62         }
    63 
    64         int sum=topsort();
    65         if(sum!=m)printf("NO
    ");
    66         else printf("YES
    ");
    67         /*
    68         通过这个循环可以得到最终每个节点的入度,如果是合法的拓扑序列,最终的结果应当都是-1
    69         for(i=1;i<=m;i++)
    70         printf("%d ",count[i]);
    71         printf("
    ");
    72         通过下面这个循环可以得到最终一个拓扑序列(如果合法),这个序列可能只是合法序列当中的一个
    73         for(i=1;i<=m;i++)
    74         printf("%d ",stack[i]);
    75         printf("
    ");
    76         */
    77     }
    78     return 0;
    79 }
    View Code

    简化后的代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 struct vode
     5 {
     6     int v;
     7     struct vode *next;
     8 };
     9 struct vode *f[300];
    10 int m,n;
    11 int rudu[300];
    12 int stack[300],top;
    13 void hs()
    14 {
    15     int i,k=0;
    16     while(k=!k)
    17     for(i=1;i<=m;i++)
    18     if(rudu[i]==0)
    19     {
    20         k=0;
    21         rudu[i]--;
    22         stack[top++]=i;
    23         struct vode *p;
    24         for(p=f[i];p!=NULL;p=p->next)
    25         rudu[p->v]--;
    26         break;
    27     }
    28 }
    29 int main()
    30 {
    31     while(scanf("%d%d",&m,&n)!=EOF)
    32     {
    33         memset(f,0,sizeof(f));
    34         memset(rudu,0,sizeof(rudu));
    35         memset(stack,0,sizeof(stack));
    36         top=0;
    37         int i;
    38         for(i=1;i<=n;i++)
    39         {
    40             int u,v;
    41             scanf("%d%d",&u,&v);
    42             rudu[v]++;
    43             struct vode *p;
    44             p=(struct vode *)malloc(sizeof(struct vode));
    45             p->v=v;
    46             p->next=f[u];
    47             f[u]=p;
    48         }
    49         hs();
    50         /*//下面的循环可以显示出拓扑序列
    51         for(i=0;i<=top-1;i++)
    52         printf("%d ",stack[i]);
    53         printf("
    ");
    54         */
    55         if(top==m)printf("YES
    ");
    56         else printf("NO
    ");
    57     }
    58     return 0;
    59 }
    View Code

    测试数据:

    5 4

    1 3

    2 3

    3 4

    3 5

    输出:

    YES

    -1 -1 -1 -1 -1

    1 2 3 4 5

    测试连接:http://wenku.baidu.com/view/bb32ee2e4b73f242336c5f53.html

  • 相关阅读:
    预备作业2
    预备作业
    虚拟机安装&Linux初探
    20155330预备作业2:做中学——实践中思考
    预备作业:你期望的师生关系是什么?
    2017-2018-1 学号20155329 《信息安全系统设计基础》第5周学习总结
    2017-2018-1 学号20155329_5332_5302《信息安全系统设计基础》实验一 开发环境的熟悉
    再装虚拟机及git
    2017-2018-1 学号20155329 《信息安全系统设计基础》第4周学习总结
    2017-2018-1 学号20155329 《信息安全系统设计基础》第4周学习总结
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/3247680.html
Copyright © 2011-2022 走看看