1. 程式人生 > 實用技巧 >POJ 1094 Sorting It All Out

POJ 1094 Sorting It All Out

題目連結:POJ 1094

Describe:
An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B, C, D implies that A < B, B < C and C < D. in this problem, we will give you a set of relations of the form A < B and ask you to determine whether a sorted order has been specified or not.
Input:
Input consists of multiple problem instances. Each instance starts with a line containing two positive integers n and m. the first value indicated the number of objects to sort, where 2 <= n <= 26. The objects to be sorted will be the first n characters of the uppercase alphabet. The second value m indicates the number of relations of the form A < B which will be given in this problem instance. Next will be m lines, each containing one such relation consisting of three characters: an uppercase letter, the character "<" and a second uppercase letter. No letter will be outside the range of the first n letters of the alphabet. Values of n = m = 0 indicate end of input.
Output:
For each problem instance, output consists of one line. This line should be one of the following three:

Sorted sequence determined after xxx relations: yyy...y.
Sorted sequence cannot be determined.
Inconsistency found after xxx relations.

where xxx is the number of relations processed at the time either a sorted sequence is determined or an inconsistency is found, whichever comes first, and yyy...y is the sorted, ascending sequence.
Sample Input:
4 6
A<B
A<C
B<C
C<D
B<D
A<B
3 2
A<B
B<A
26 1
A<Z
0 0
Sample Output:
Sorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations.
Sorted sequence cannot be determined.

題目大意:

給n個連續的字母,m個判斷語句,問在得到多少語句之後可以判斷出這些字母構成一個環,或者一個排序,亦或者不能確定。

解題思路:

每次讀入一組資料,就拓撲排序判斷一下,具體見程式碼的詳細註釋。根據題意和輸入輸出,會發現此題跟圖有關,從而想到最終的排序用拓撲排序。

此題也附上快150行的的一次寫的錯誤程式碼,想的太複雜了。

AC程式碼:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 // arr用來儲存圖,in用來儲存入度,ans用來儲存排好序的序列
 6 int arr[26][26],in[26],ans[26];
 7 void init(int n) // 初始化函式
 8 {
 9     for(int i = 0; i < n; i++)
10         for(int j = 0; j < n; j++)
11             arr[i][j] = 0;
12     for(int i = 0; i < n; i++)
13         in[i] = 0;
14 }
15 int topo(int n)
16 {
17     int tmp[26],t,f = 1,cont = 0;
18     for(int i = 0; i < n; i++) tmp[i] = in[i]; // 臨時陣列複製入度陣列,防止入度陣列改變
19     for(int i = 0; i < n; i++)
20     {
21         cont = 0; // 表示入度為0的個數
22         t = -1; // 儲存入度為0的序號
23         for(int j = 0; j < n; j++) // 迴圈尋找入度為0的
24         {
25             if(tmp[j] == 0)
26             {
27                 cont++;
28                 t = j;
29             }
30         }
31         if(cont > 1) f = 0; // 如果入度為零的數目大於1,說明暫時不能確定,但是不能直接return
32         // 因為可能還存在成環的情況我們沒有檢測出來,所以先記錄下來
33         if(cont == 0) return 2; // 如果沒有一個入度為0的,說明成環了
34         ans[i] = t; // 記錄到答案陣列
35         tmp[t] = -1; // 注意,不能忘記這一步,表示該點已經搜尋到過了,不能重複搜尋
36         for(int j = 0; j < n; j++) // 相連的點入度都減一
37             if(arr[t][j] == 1)
38                 tmp[j]--;
39     }
40     return f;
41 }
42 int main()
43 {
44     int n,m,x,y,f,cnt,t; // n,m,a,b,c為題目變數,f為標誌,cnt為計數器,t為中間變數
45     char a,b,c;
46     while(~scanf("%d%d",&n,&m) && n+m)
47     {
48         cnt = 0; // 各種初始化
49         f = 1;
50         init(n);
51         while(m--)
52         {
53             scanf("\n%c%c%c",&a,&b,&c);
54             if(f == 1)
55             {
56                 x = a-'A'; // 資料型別轉換
57                 y = c-'A';
58                 arr[x][y] = 1; // 有向圖新增一條邊
59                 in[y]++; // 入度加一
60                 cnt++;
61                 t = topo(n); // 進行一次判斷
62                 if(t == 1) // 如果能排序
63                 {
64                     printf("Sorted sequence determined after %d relations: ",cnt);
65                     for(int i = 0; i < n; i++) printf("%c",ans[i]+'A');
66                     printf(".\n");
67                     f = 0;
68                 } else if(t == 2) { // 如果成環
69                     printf("Inconsistency found after %d relations.\n",cnt);
70                     f = 0;
71                 }
72             }
73         } // 如果最終都沒確定,則無法確定
74         if(f == 1) printf("Sorted sequence cannot be determined.\n");
75     }
76     return 0;
77 }

錯誤程式碼:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 using namespace std;
  6 struct node
  7 {
  8     int time,id,ex;
  9     node *next;
 10 } arr[26];
 11 int n,m,flag,cnt,f[26],d[26],bp[26];
 12 void backup(int n)
 13 {
 14     for(int i = 0; i < n; i++)
 15         bp[i] = arr[i].time;
 16 }
 17 void recover(int n)
 18 {
 19     for(int i = 0; i < n; i++)
 20         arr[i].time = bp[i];
 21     memset(bp,0,sizeof(bp));
 22 }
 23 void init(int n)
 24 {
 25     for(int i = 0; i < n; i++)
 26     {
 27         arr[i].id = i;
 28         arr[i].ex = 0;
 29         arr[i].time = 0;
 30         arr[i].next = NULL;
 31     }
 32     for(int i = 0; i < n; i++)
 33         f[i] = 0;
 34 }
 35 int num(int n)
 36 {
 37     for(int i = 0; i < n; i++)
 38     {
 39         if(arr[i].time == 0 && f[i] == 0 && arr[i].ex == 1)
 40         {
 41             return i;
 42         }
 43     }
 44     return -1;
 45 }
 46 bool check(int n)
 47 {
 48     backup(n);
 49     int t;
 50     while(true)
 51     {
 52         t = num(n);
 53         if(t == -1) break;
 54         f[t] = 1;
 55         node *tmp = arr[t].next;
 56         while(tmp != NULL) {arr[tmp->id].time--;tmp = tmp->next;}
 57     }
 58     for(int i = 0; i < n; i++)
 59     {
 60         if(f[i] == 0 && arr[i].ex == 1)
 61             return false;
 62     }
 63     return true;
 64 }
 65 bool istopo(int n)
 66 {
 67     for(int i = 0; i < n; i++)
 68         if(arr[i].ex == 0)
 69             return false;
 70     return true;
 71 }
 72 void topo(int n)
 73 {
 74     int t;
 75     while(true)
 76     {
 77         t = num(n);
 78         if(t == -1) break;
 79         f[t] = 1;
 80         node *tmp = arr[t].next;
 81         while(tmp != NULL) {arr[tmp->id].time--; tmp = tmp->next;}
 82         printf("%c",t+'A');
 83     }
 84 }
 85 void dfs(int t)
 86 {
 87     d[t] = 1;
 88     node *tmp = arr[t].next;
 89     while(tmp != NULL)
 90     {
 91         dfs(tmp->id);
 92         tmp = tmp->next;
 93     }
 94 }
 95 int main()
 96 {
 97     while(~scanf("%d%d",&n,&m) && n+m)
 98     {
 99         memset(d,0,sizeof(d));
100         memset(f,0,sizeof(f));
101         flag = -1; //-1表示正常,-2表示不能拓撲,-3表示可以拓撲
102         cnt = 0;
103         init(n);
104         int x,y;
105         char a,b,c;
106         while(m--)
107         {
108             scanf("\n%c%c%c",&a,&b,&c);
109             if(flag == -1)
110             {
111                 x = a-'A';
112                 y = c-'A';
113                 node *tmp = (node*)malloc(sizeof(node));
114                 node *temp = &arr[x];
115                 while(temp->next != NULL) temp = temp->next;
116                 tmp->id = y;
117                 tmp->next = NULL;
118                 temp->next = tmp;
119                 arr[x].ex = 1;
120                 arr[y].ex = 1;
121                 arr[y].time++;
122                 cnt++;
123                 if(!check(n)) flag = -2;
124                 recover(n);
125                 memset(f,0,sizeof(f));
126                 if(istopo(n) && flag == -1) flag = -3;
127             }
128         }
129         if(flag == -2) printf("Inconsistency found after %d relations.\n",cnt);
130         else if(flag == -3) {
131             printf("Sorted sequence determined after %d relations: ",cnt);
132             topo(n);
133             printf(".\n");
134         } else if(flag == -1) {
135             dfs(num(n));
136             int ff = 1;
137             for(int i = 0; i < n; i++)
138                 if(d[i] == 0)
139                     ff = 0;
140             if(ff == 0) printf("Sorted sequence cannot be determined.\n");
141             else {
142                 printf("Sorted sequence determined after %d relations: ",cnt);
143                 topo(n);
144                 printf(".\n");
145             }
146         }
147     }
148     return 0;
149 }
View Code

Tips:

關於拓撲排序,一般用刪邊法,即找到一個入度為0的點並輸出,然後刪掉這個點,並且同時刪掉跟它相連的邊,然後重複上述步驟。這個方法也可以用來判斷圖中是否存在迴路。(判斷圖是否連通用dfs)