拓扑排序[TopologicalSort]

闲来无事,看到了拓扑排序就学习了一下。

拓扑排序:

  算导上说是使用深搜来对有向无环图进行排序,得到一种线性次序。不过深搜的理解还理解不到。估计是深搜学的不怎么样吧!

  说说我理解的这个线性次序吧。我认为算导上的例子就特别好。早上起来穿衣服的顺序。进过拓扑排序,就能得到一个正确的穿衣次序。

算法执行顺序:
   第一步,找到入度为以的结点,入队。

   第二步,删除与找到的结点相连的边,继续第一步。

   直到所有的结点入队。队列中的一个线性顺序就为一个拓扑排序

现在,以算导上的穿衣例子来实现。


形成环的条件是,入度为0的结点不存在了。

比如,一个结点入队了,剩下的结点也可能成环。

拓扑排序[TopologicalSort]_第1张图片



//
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int N=10;
int Enter[N];//来记录每个结点的入度.
bool Vis[N];

int main()
{
//    freopen("11.txt","r",stdin);
    int n,m;//n个结点,m条边.
    vector v[N];//邻接表存图.
    queue q;
    int first,than;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>first>>than;
        v[first].push_back(than);
        Enter[than]++;
    }
    while(q.size()

当然,穿衣的顺序可能有多种,这里,只能跑出来一种,但是,他是正确的。

当然对于,条件比较少的问题,其问题的解可能是不唯一的。

对于拓扑排序来说,最基础的问题结构应该是,比赛排名这一种问题吧。

NYOJ 349&&496就是这类问题。

496链接

这个题意就是,是否存在一种一种唯一顺序。

 
#include 
#include 
#include 
#include 
#include 
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;

const int N=30;
bool Map[N][N];
int Enter[N];
char Sorted[N];
int n,m;
char a,b;

bool TopSort(){
    int top=0;
    while(1){
        int count=0,p;
        for(int i=1;i<=n;i++)
        if(Enter[i]==0){
            count++;
            p=i;
        }
        if(count!=1)  break;
        else{
            Sorted[top++]=p+'A'-1;
            Enter[p]=-1;
            for(int i=1;i<=n;i++)
            if(Map[p][i]){
                Map[p][i]=false;
                Enter[i]--;}
        }
    }
    Sorted[top]='\0';
    if(strlen(Sorted)==n) return true;
    else return false;
}

int main(){
    int T;
    cin>>T;
    while(T--){
         CLR(Enter,0);CLR(Map,0);
         cin>>n>>m;
         for(int i=1;i<=m;i++){
             cin>>a>>b;
             Enter[b-'A'+1]++;Map[a-'A'+1][b-'A'+1]=true;
         }
         if(TopSort()) printf("%s\n",Sorted);
         else printf("No Answer\n");
    }
    return 0;
}        

用vector实现了一下。

#include 
#include 
#include 
#include 
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;

const int N=30;
char Sorted[N];
int n,m,Enter[N];
vector v[N];

bool TopoSort(){
    int top=0;
    while(1){
        int count=0,p;
        for(int i=1;i<=n;i++)
        if(Enter[i]==0){
            count++;
            p=i;
        }
        if(count!=1) break;
        else{
            Enter[p]=-1;
            Sorted[top++]=p+'A'-1;
            for(unsigned i=0;i



349题目链接

这个题题目的意思:

也是确定一个排序。

在前几个偏序回得出结论。

结论有,矛盾了,有确定的序列,没有确定的序列但也不矛盾。

#include 
#include 
#include 
#include 
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;

const int N=30;
char Sorted[N];
int n,m;

int TopSort(bool map[][N],int enter[]){
    int top=0;
    bool mark=false;
      for(int k=1;k<=n;k++){
        int count=0,p;
        for(int i=1;i<=n;i++){
            if(enter[i]==0){
                p=i;
                count++;
            }
        }
        if(count==0) return -1;
        else if(count>1) {
            mark=true;
        }
        //该题下,因为后续的可能产生矛盾所以,即使找到的序列不唯一
        //也要先确定一种序列看看是否后续是否后续是否回矛盾.
        //而,序列不唯一只需要标记一下就可以了.
        enter[p]=-1;
        Sorted[top++]=p+'A'-1;
        for(int i=1;i<=n;i++){
            if(map[p][i]) enter[i]--;
        }
    }
    Sorted[top]='\0';
    if(mark) return 0;
    else return 1;
}

int main()
{
//    freopen("11.txt","r",stdin);
    while(cin>>n>>m&&(n||m)){
        bool Map[N][N],flag=false;
        int Enter[N];
        CLR(Map,0);CLR(Enter,0);
        getchar();
        char a,b;
        for(int k=1;k<=m;k++){
            scanf("%c<%c",&a,&b);
            getchar();
            Map[a-'A'+1][b-'A'+1]=true;
            Enter[b-'A'+1]++;
            bool map[N][N];//作为传入值用.
            int enter[N];
            CLR(map,0);CLR(enter,0);
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++)
                map[i][j]=Map[i][j];
                enter[i]=Enter[i];
            }
            if(!flag){
                int ans=TopSort(map,enter);
                if(ans==-1){
                    printf("Inconsistency found after %d relations.\n",k);
                    flag=true;
                }
                else if(ans==1){
                    printf("Sorted sequence determined after %d relations: %s.\n",k,Sorted);
                    flag=true;
                }
        }
    }
    if(!flag) printf("Sorted sequence cannot be determined.\n");}
    return 0;
}

这道的题的关键在于,如果序列不唯一,也要继续topo下去,因为后续的序列可能会产生矛盾。如果直接跳出,就判断不到后面的序列是否矛盾。


拓扑排序就到这里了。

总结几点:

第一,拓扑排序,排的是有向无环图。

第二,要深刻理解这个无环。可能有的结点进队后,剩余的结点就成环了,这样也是不能得到一个合理是序列的。

第三,以后要弄个明白这个深搜的思想。


你可能感兴趣的:(拓扑排序[TopologicalSort])