拓撲排序以及題型演練

拓撲排序主要是判斷一個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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章