程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> poj 1270 || uva 124 Following Orders (拓撲排序)

poj 1270 || uva 124 Following Orders (拓撲排序)

編輯:C++入門知識

題目大意:    第一行給出字符串(小寫字母),表示出現的字符類型

                   第二行是約束關系,a1 b1 a2 b2 a3 b3.....ai bi,表示ai必須在bi前面

                   按照字典序輸出所有滿足約束條件的序列

                   如:


                   y z x

                   x z

                   xyz

                   xzy

                   yxz


解題思路:    題目要求字典序輸出,先把給出第一行字符串排序

                   所有的約束條件變成有向圖的邊,x z表示頂點x到頂點z的邊

                   序列的情況是否跟有向圖有沖突,不沖突則正確,否則捨去


                   用深搜把所有滿足的情況都搜索一邊


                   每次找到入度為0的頂點就開始進入下一層,存入a[len],並且把與這個頂點相連的點的入度都減1


                   直到搜索到的層數len等於字符串的長度,就輸出a[ ]


                   也就是在搜索過程中融合拓撲排序的思想,直到不存在入度為0的頂點為止


                   剪枝:   把字符串轉換成數字可以大大提高效率,如y z x 轉換為 2 3 1

代碼:


[cpp]
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <stdlib.h>  
#include <algorithm>  
using namespace std; 
#define MAX 200  
char ch1[MAX],ch2[MAX],ch3[MAX]; 
int n,m,zm[MAX],edge[MAX][MAX],to[MAX],visit[MAX],a[MAX]; 
 
bool comp(char a,char b) 

    return a<b; 

 
void DFS(int len) 

    int i,j; 
    if(len==n)   //層數等於字符串長度則輸出  
    { 
        for(i=0;i<n;i++) 
        { 
            printf("%c",ch1[a[i]]); 
        } 
        printf("\n"); 
        return ; 
    } 
    for(i=0;i<n;i++) 
    { 
        if(!visit[i]&&!to[i]) 
        { 
            for(j=0;j<n;j++)   //把與這個頂點相連的點入度減1  
            { 
                if(edge[i][j]==1) 
                { 
                    to[j]--; 
                } 
            } 
            visit[i]=1;        //標記此點訪問過  
            a[len]=i; 
            DFS(len+1); 
            for(j=0;j<n;j++)   //還原現場: 把減掉的入度加回去  
            { 
                if(edge[i][j]==1) 
                { 
                    to[j]++; 
                } 
            } 
            visit[i]=0;        //還原現場  
        } 
    } 
    return ; 

 
int main() 

    int i,k,pd=0; 
    while(gets(ch3)) 
    { 
        if(pd==0) 
            pd=1; 
        else 
            printf("\n");  //測試用例之間輸出空行  
        gets(ch2); 
        memset(zm,-1,sizeof(zm)); 
        memset(edge,-1,sizeof(edge)); 
        memset(to,0,sizeof(to)); 
        memset(visit,0,sizeof(visit)); 
        for(i=0,n=0;ch3[i]!='\0';i++)   //去除空格  
        { 
            if(ch3[i]==' ') 
                continue; 
            ch1[n++]=ch3[i]; 
        } 
        sort(ch1,ch1+n,comp);           //排序  
        for(i=0;i<n;i++)                //字符串1處理,把字母轉化成0到n-1的邊  
        { 
            zm[ch1[i]-'a']=i; 
        } 
        for(i=0,k=0;ch2[i]!='\0';i+=4)  //字符串2處理,構建有向圖  
        { 
            edge[zm[ch2[i]-'a']][zm[ch2[i+2]-'a']]=1; 
            to[zm[ch2[i+2]-'a']]++;     //頂點入度+1  
        } 
        DFS(0); 
    //    printf("\n");    這樣輸出空行poj可以過,UVA會WA  
    } 
    return 0; 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define MAX 200
char ch1[MAX],ch2[MAX],ch3[MAX];
int n,m,zm[MAX],edge[MAX][MAX],to[MAX],visit[MAX],a[MAX];

bool comp(char a,char b)
{
    return a<b;
}

void DFS(int len)
{
    int i,j;
    if(len==n)   //層數等於字符串長度則輸出
    {
        for(i=0;i<n;i++)
        {
            printf("%c",ch1[a[i]]);
        }
        printf("\n");
        return ;
    }
    for(i=0;i<n;i++)
    {
        if(!visit[i]&&!to[i])
        {
            for(j=0;j<n;j++)   //把與這個頂點相連的點入度減1
            {
                if(edge[i][j]==1)
                {
                    to[j]--;
                }
            }
            visit[i]=1;        //標記此點訪問過
            a[len]=i;
            DFS(len+1);
            for(j=0;j<n;j++)   //還原現場: 把減掉的入度加回去
            {
                if(edge[i][j]==1)
                {
                    to[j]++;
                }
            }
            visit[i]=0;        //還原現場
        }
    }
    return ;
}

int main()
{
    int i,k,pd=0;
    while(gets(ch3))
    {
        if(pd==0)
            pd=1;
        else
            printf("\n");  //測試用例之間輸出空行
        gets(ch2);
        memset(zm,-1,sizeof(zm));
        memset(edge,-1,sizeof(edge));
        memset(to,0,sizeof(to));
        memset(visit,0,sizeof(visit));
        for(i=0,n=0;ch3[i]!='\0';i++)   //去除空格
        {
            if(ch3[i]==' ')
                continue;
            ch1[n++]=ch3[i];
        }
        sort(ch1,ch1+n,comp);           //排序
        for(i=0;i<n;i++)                //字符串1處理,把字母轉化成0到n-1的邊
        {
            zm[ch1[i]-'a']=i;
        }
        for(i=0,k=0;ch2[i]!='\0';i+=4)  //字符串2處理,構建有向圖
        {
            edge[zm[ch2[i]-'a']][zm[ch2[i+2]-'a']]=1;
            to[zm[ch2[i+2]-'a']]++;     //頂點入度+1
        }
        DFS(0);
    //    printf("\n");    這樣輸出空行poj可以過,UVA會WA
    }
    return 0;
}
方法2:       利用STL庫裡面的next_permutation()函數,把所有的字符串全排列都找出

                   把符合情況的字符串輸出,不符合的捨去


[cpp]
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <stdlib.h>  
#include <algorithm>  
using namespace std; 
#define MAX 200  
char ch1[MAX],ch2[MAX],ch3[MAX]; 
int n,m,zm[MAX],edge[MAX][MAX],to[MAX],visit[MAX],a[MAX]; 
 
bool comp(char a,char b) 

    return a<b; 

 
int Topsort(char ch[]) 

    int i,j; 
    for(i=n-1;i>0;i--) 
    { 
        for(j=i-1;j>=0;j--) 
        { 
            if(edge[zm[ch[i]-'a']][zm[ch[j]-'a']]==1) 
                return 0; 
        } 
    } 
    return 1; 

 
int main() 

    int i,k,pd=0; 
    while(gets(ch3)) 
    { 
        if(pd==0) 
            pd=1; 
        else 
            printf("\n"); 
        gets(ch2); 
        memset(zm,-1,sizeof(zm)); 
        memset(edge,-1,sizeof(edge)); 
        memset(to,0,sizeof(to)); 
        memset(visit,0,sizeof(visit)); 
        for(i=0,n=0;ch3[i]!='\0';i++)   //去空格  
        { 
            if(ch3[i]==' ') 
                continue; 
            ch1[n++]=ch3[i]; 
        } 
        ch1[n]='\0'; 
        sort(ch1,ch1+n,comp);           //排序  
        for(i=0;i<n;i++)                //字符串1處理,把字母轉化成0到n-1的邊  
        { 
            zm[ch1[i]-'a']=i; 
        } 
        for(i=0,k=0;ch2[i]!='\0';i+=4)  //字符串2處理,構建有向圖  
        { 
            edge[zm[ch2[i]-'a']][zm[ch2[i+2]-'a']]=1; 
            to[zm[ch2[i+2]-'a']]++; 
        } 
        if(Topsort(ch1))              //符合限制條件則輸出  
            printf("%s\n",ch1); 
        while(next_permutation(ch1,ch1+n)) 
        { 
            if(Topsort(ch1))          //符合限制條件則輸出  
                printf("%s\n",ch1); 
        } 
    //    printf("\n");  
    } 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved