ACM/ICPC 之 拓扑排序范例(POJ1094-POJ2585)

两道拓扑排序问题的范例,用拓扑排序解决的实质是一个单向关系问题

 

 

POJ1094(ZOJ1060)-Sortng It All Out    

 

  题意简单,但需要考虑的地方很多,因此很容易将code写繁琐了,会给力求code精简的强迫症患者一个警醒- –

  题意:给出m组逻辑关系式,求n个字母间的排序,分排序成功排序矛盾不能确定三种情况输出相应语句

  题解:拓扑排序,访问入度为0的结点,邻接点入度-1,然后继续访问入度为0的结点…直到访问完成为止

     需要注意的地方在于三种情况根据最早确定的情况来输出,例如先排序完成,但后面的关系式表明排序矛盾,此时按照先排序完成得到的序列输出。

     

 1 //一道考查拓扑排序的经典例题
 2 //POJ1094-ZOJ1060
 3 //Time:0Ms    Memory:188K
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<vector>
 8 using namespace std;
 9 
10 #define MAX 27
11 
12 struct Letter {
13     int in;    //入度
14     int v;
15     vector<int> p;
16 }letter[MAX];
17 
18 int n, m;
19 char seq[MAX];
20 
21 int topSort(int total)
22 {
23     memset(seq, 0, sizeof(seq));
24     int tmp[MAX];    //临时入度数组
25     for (int i = 0; i < n; i++)
26         tmp[i] = letter[i].in;
27 
28     bool correct = true;    //是否可行
29     for (int i = 0; i < total;i++)
30     {
31         int cur;    //当前字母位置
32         int cnt = 0;    //入度为0的个数
33         for (int i = 0; i < n; i++)
34             if (tmp[i] == 0)
35             {
36                 cur = i;
37                 cnt++;
38             }
39         if (cnt == 0) return -1;
40         if (cnt > 1) correct = false;    //多选时-不可行但须判断是否矛盾
41         for (int i = 0; i < letter[cur].p.size(); i++)
42             tmp[letter[cur].p[i]]--;
43         seq[i] = cur + 'A';
44         tmp[cur]--;
45     }
46     return correct;
47 }
48 
49 int main()
50 {
51     //freopen("in.txt", "r", stdin);
52     while (scanf("%d%d", &n, &m), n && m)
53     {
54         int total = 0;    //输入字母总个数
55         bool flag = false;    //得到结论
56         memset(letter, 0, sizeof(letter));
57         for (int i = 1; i <= m; i++)
58         {
59             char formula[4];
60             scanf("%s", formula);
61             if (flag) continue;    //已得出结论
62             int small = formula[0] - 'A';
63             int big = formula[2] - 'A';
64             total += !letter[small].v + !letter[big].v;
65             letter[small].v = letter[big].v = 1;
66             letter[small].p.push_back(big);
67             letter[big].in++;
68             int key = topSort(total);
69             if (key == -1)
70             {
71                 printf("Inconsistency found after %d relations.\n", i);
72                 flag = true;
73             }
74             else if (key == 1)
75             {
76                 printf("Sorted sequence determined after %d relations: %s.\n", i, seq);
77                 flag = true;
78             }
79         }
80         if (!flag)
81             printf("Sorted sequence cannot be determined.\n");
82     }
83     return 0;
84 }

 

 

 

POJ2585(ZOJ2193)-Window Pains

 

  题意:给定一组出现在固定位置的预设窗口,求可否使得这些窗口按照先后次序得到给定样例的显示状态。

  题解:拓扑排序,用覆盖表示先后关系,若最终无环则可以按照一定次序得到样例,如果有环,那么就与覆盖这种单向关系矛盾。

 

 1 //拓扑排序-窗口覆盖问题
 2 //单向关系问题
 3 //Time:16Ms    Memory:176K
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<vector>
 8 #include<queue>
 9 using namespace std;
10 
11 #define MAX 4
12 
13 //预设窗口
14 struct Map {
15     int size;    //覆盖个数
16     int num[MAX];
17 }map[MAX][MAX];
18 
19 struct Area {
20     vector<int> cover;
21     int in;        //入度
22 }area[10];
23 
24 int win[MAX][MAX];    //实际窗口
25 int mov[4][2] = { {0,0}, {0,1}, {1,0}, {1,1} };
26 
27 void init()
28 {
29     for (int i = 0; i < 3; i++)
30         for (int j = 0; j < 3; j++)
31             for (int k = 0; k < 4; k++)
32             {
33                 int tx = i + mov[k][0];
34                 int ty = j + mov[k][1];
35                 map[tx][ty].num[map[tx][ty].size++] = i * 3 + j + 1;
36             }
37 }
38 
39 //拓扑排序
40 bool topology()
41 {
42     for (int i = 0; i < 9;i++)
43     {
44         int cur = 0;
45         while (++cur < 10 && area[cur].in);    //找出入度为0的点
46         if (cur == 10) return false;    //存在环-非单向关系
47         area[cur].in--;
48 
49         vector<int> cover = area[cur].cover;
50         for (int i = 0; i < cover.size(); i++)
51             area[cover[i]].in--;
52     }
53     return true;
54 }
55 
56 int main()
57 {
58     init();
59     
60     char command[12];
61     while (scanf("%s", command), strcmp(command, "ENDOFINPUT"))
62     {
63         memset(area, 0, sizeof(area));
64         for (int i = 0; i < 4; i++)
65             for (int j = 0; j < 4; j++)
66                 scanf("%d", &win[i][j]);
67         scanf("%s", command);
68 
69         //Area-Cover
70         for (int i = 0; i < 4; i++)
71             for (int j = 0; j < 4; j++)
72                 for (int k = 0; k < map[i][j].size; k++)
73                 {
74                     vector<int> cover = area[win[i][j]].cover;
75                     int num = map[i][j].num[k];
76                     if (num != win[i][j] && cover.end() == find(cover.begin(), cover.end(), num))    //去重
77                     {
78                         area[win[i][j]].cover.push_back(num);
79                         area[num].in++;
80                     }
81                 }
82 
83         if (topology())
84             printf("THESE WINDOWS ARE CLEAN\n");
85         else printf("THESE WINDOWS ARE BROKEN\n");
86     }
87 
88     return 0;
89 }

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/Inkblots/p/5348185.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞