拓扑排序以及题型演练

拓扑排序主要是判断一个AOV网中是否存在有向环?在图论的题目广泛应用到.
主要有两个步骤
步骤1: 在有向图中选一个没有前驱的顶点且输出之
步骤2: 从图中删除该顶点和所有以它为尾的弧

模板

void topsort()
{
    int i,j;
	for(i=0; i<n; i++)     //n为顶点数
    {
        for(j=1; j<=n; j++)
        {
            if(indegree[j]==0)  //入度数组,记录了顶点的入度数
            {
                indegree[j]--;
                pur[i]=j;
	for(int l=1; l<=n; l++)//从图中删除该顶点和所有以它为尾的弧
                {
			 if(Map[j][l]) 
			 indegree[l]--;                             
	               }
                break;
            }
	         if(j>=n)//没有出现入度为0的顶点,则证明出现了环
            {
                cout<<"尼玛!存在环\n"<<endl;
                return;
            }
        }
    }
}

下面给两个HDU的关于拓扑排序的基础题
HDU1285
解题思路:直接套用模板即可.不过有坑点,记得判断重边

/*
拓扑排序
步骤1: 在有向图中选一个没有前驱的顶点且输出之
步骤2: 从图中删除该顶点和所有以它为尾的弧
*/
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define M 500
int n,m;          //n代表顶点数
int Map[M+1][M+1];
int pur[M+1];
int indegree[M];      //入度
bool vis[M][M];
bool flag;
void topsort()
{
    int i,j,l;
    for(i=0;i<n;++i){
        for(j=1;j<=n;++j)
    {
        if(indegree[j]==0)
        {
            indegree[j]--;
            pur[i]=j;
            for(l=1;l<=n;++l)//从图中删除该顶点和所有以它为尾的弧
            {
                if(Map[j][l])
                    indegree[l]--;
            }
            break;
        }
//        if(j>=n)
//        {
//            flag=false;
//           // cout<<"尼玛存在环"<<endl;
//            return ;
//        }
    }
    }
}
void solve()
{
    int i,j,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
    memset(vis,false,sizeof(vis));
    memset(Map,0,sizeof(Map));
    memset(pur,0,sizeof(pur));
    memset(indegree,0,sizeof(indegree));
    flag=true;
    while(m--)
    {
        scanf("%d%d",&a,&b);
		if(!vis[a][b])     //判断重边
        {
        Map[a][b]=1;
        indegree[b]++;
        vis[a][b]=true;
        }
    }
    topsort();
   //if(flag)
   // {
    for(int i=0;i<n;++i)
    printf("%d%c",pur[i],i==n-1?'\n':' ');
 //   }
    }
}
int main()
{
   solve();
//    cout << "Hello world!" << endl;
    return 0;
}

HDU3342
这个不用输出序列,只需要拓扑排序的过程中判断是否存在环即可.当然出现了一个人既是师傅又是徒弟的情况就直接gg了。这里注意还是要判断重边(HDU坑点真多).再啰嗦下解释下输入.输入的n代表人数,m代表关系数.m等于0结束输入.(本人一开始把n当然了样例数,结果一直WA.智商捉急啊)

#include <iostream>
#include <cstdio>
#include <cstring>
#define M 101
using namespace std;
bool vis[M][M];
int Map[M][M];
int indegree[M];
int num[M],k;         
bool vis1[M];
bool flag;
bool topsort()
{
    int i,j,l;
    for(i=0; i<k; ++i)
    {
        for(j=0; j<k; ++j)
        {
            if(indegree[num[j]]==0)
            {
                indegree[num[j]]--;
              //  printf("%d ",num[j]);
                for(l=0; l<k; ++l)
                {
                    if(Map[num[j]][num[l]])
                        indegree[num[l]]--;
                }
                break;
            }
            if(j>=k-1)
                return false;
        }
    }
    return true;
}
int main()
{
    int t,i,j,a,b,n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!m) break;
        memset(vis1,false,sizeof(vis1));
        memset(num,0,sizeof(num));
        memset(vis,false,sizeof(vis));
        memset(Map,0,sizeof(Map));
        memset(indegree,0,sizeof(indegree));
        flag=true;
        k=0;
        for(i=0; i<m; ++i)
        {
            scanf("%d%d",&a,&b);
            if(a==b) flag=false;
            if(flag)
            {
                if(!vis[a][b])
                {
                    if(!vis1[a])
                    {
                        num[k++]=a;
                        vis1[a]=true;
                    }
                    if(!vis1[b])
                    {
                        num[k++]=b;
                        vis1[b]=true;
                    }
                    Map[a][b]=1;
                    indegree[b]++;
                    vis[a][b]=true;
                }
            }
        }
//            for(i=0;i<k;++i)
//                printf("%d ",num[i]);
        if(!flag)
        {
            printf("NO\n");
            continue;
        }
        if(topsort())
            printf("YES\n");
        else
            printf("NO\n");
    }
//   cout << "Hello world!" << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章