zoukankan      html  css  js  c++  java
  • 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.
    ", i);
    72                 flag = true;
    73             }
    74             else if (key == 1)
    75             {
    76                 printf("Sorted sequence determined after %d relations: %s.
    ", i, seq);
    77                 flag = true;
    78             }
    79         }
    80         if (!flag)
    81             printf("Sorted sequence cannot be determined.
    ");
    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
    ");
    85         else printf("THESE WINDOWS ARE BROKEN
    ");
    86     }
    87 
    88     return 0;
    89 }
    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    Codeforces Round #631 (Div. 1) B. Dreamoon Likes Sequences 题解(思维+求贡献)
    牛客练习赛66 C公因子 题解(区间gcd)
    evincevim控喜欢的pdf阅读器
    水手郑智化
    使用diskpart管理自己的分区
    Hacker's Browser
    How Browser Works
    解决vim ctags R失败的问题
    ubuntu更改登录对话框
    使用bcdedit删除多个Windows系统
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5348185.html
Copyright © 2011-2022 走看看