USACO 4.4 Frame up Topological Sort

题目描述

看下面的五张 9 x 8 的图像:

........   ........   ........   ........   .CCC....
EEEEEE..   ........   ........   ..BBBB..   .C.C....
E....E..   DDDDDD..   ........   ..B..B..   .C.C....
E....E..   D....D..   ........   ..B..B..   .CCC....
E....E..   D....D..   ....AAAA   ..B..B..   ........
E....E..   D....D..   ....A..A   ..BBBB..   ........
E....E..   DDDDDD..   ....A..A   ........   ........
E....E..   ........   ....AAAA   ........   ........
EEEEEE..   ........   ........   ........   ........

   1          2           3          4          5

现在,把这些图像按照 1—5 的编号从下到上重叠,第 1 张在最下面,第 5 张在最顶端。如果一张图像覆盖了另外一张图像,那么底下的图像的一部分就变得不可见了。我们得到下面的图像:

             .CCC....
             ECBCBB..
             DCBCDB..
             DCCC.B..
             D.B.ABAA
             D.BBBB.A
             DDDDAD.A
             E...AAAA
             EEEEEE..

对于这样一张图像,计算构成这张图像的矩形图像从底部到顶端堆叠的顺序。

下面是这道题目的规则:

矩形的边的宽度为 1 ,每条边的长度都不小于 3 。

矩形的每条边中,至少有一部分是可见的。注意,一个角同时属于两条边。

矩形用大写字母表示,并且每个矩形的表示符号都不相同。

输入输出格式

输入格式:

第一行 两个用空格分开的整数:图像高 H (3 <= H <=30) 和图像宽 W (3 <= W <= 30) 。

第二行到第 H+1 行 H 行,每行 W 个字母。

输出格式:

按照自底向上的顺序输出字母。如果有不止一种情况,按照字典顺序输出每一种情况(至少会有一种合法的顺序)。

输入输出样例

输入样例#1: 
9 8
.CCC....
ECBCBB..
DCBCDB..
DCCC.B..
D.B.ABAA
D.BBBB.A
DDDDAD.A
E...AAAA
EEEEEE..
输出样例#1:
EDABC

说明

题目翻译来自NOCOW。

USACO Training Section 4.4

分析

因为每条边上都至少给出一个点,所以很容易算出四边形的所在位置和大小(其实就是四边形在四个方向上的最远坐标)。

然后进行判断谁一定在谁的上方,方法是:在每个矩形的边上,若出现了另一个矩形的符号,那么这个出现的矩形就在这个矩形的上方。然后建立一条有向边,从上方的矩形指向下方的矩形。建立边的同时累加矩形的入度(D[])。

最后进行拓扑排序,这里是DFS的版本。

注意几个地方:

  1. 60~63行的地方,在两个方向上,哪个是i,哪个是j要分清楚。例如:在横向上,i是固定的,要更新的是j。
  2. 输出注意并没有空格。
  3. 提交OJ不要加文件,查了一个小时居然是这种错误QAQ。OJ上显示是"Too many or too few lines."以至于我还认为是只输出了一种情况。结果最后发现居然提交了带文件的程序。

程序

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int MAXL = 30 + 1;
 4 const int INF = 0x3F3F3F3F;
 5 struct node
 6 {
 7     int Left, Right, Top, Bottom;
 8 }spots[27];
 9 bool flag[27][27], v[27];
10 int H, W, Head[27], p[27], CountP, D[27];
11 char frame[MAXL][MAXL];
12 // Topological Sort based on DFS
13 void dfs()
14 {
15     bool f = 0;
16     for (int i = 1; i <= 26; i++)
17         if(v[i])
18         {
19             f = 1;
20             break;
21         }
22     if(!f)
23     {
24         for (int i = 1; i <= CountP; i++)
25         {
26                 cout << (char)p[i];
27         }
28         cout << endl; 
29         return;
30     }
31     for (int i = 1; i <= 26; i++)
32         if(v[i] && D[i] == 0)
33         {
34             p[++CountP] = i + '@';
35             for (int j = 1; j <= 26; j++)
36                 if(flag[i][j])
37                     D[j]--;
38             v[i] = 0;
39             dfs();
40             for (int j = 1; j <= 26; j++)
41                 if(flag[i][j])
42                     D[j]++;
43             v[i] = 1;
44             CountP--;
45         }
46 }
47 int main()
48 {
49     for (int i = 1; i <= 26; i++)
50         spots[i].Left = INF, spots[i].Right = 0, spots[i].Top = INF, spots[i].Bottom = 0;
51     cin >> H >> W;
52     for (int i = 1; i <= H; i++)
53     {
54         scanf("%s",frame[i]+1);
55         for (int j = 1; j <= W; j++)
56         {
57             if (frame[i][j] == '.')
58                 continue;
59             int c = (int)(frame[i][j]) - (int)('A') + 1;
60             spots[c].Left = min(spots[c].Left,j);
61             spots[c].Right = max(spots[c].Right,j);
62             spots[c].Top = min(spots[c].Top,i);
63             spots[c].Bottom = max(spots[c].Bottom,i);
64             v[c] = 1;
65         }
66     }
67     for (int i = 1; i <= 26; i++)
68     {
69         if (v[i])
70         {
71             for (int j = spots[i].Left; j <= spots[i].Right; j++)
72             {
73                 if (frame[spots[i].Top][j] != '.')
74                     flag[i][frame[spots[i].Top][j]-'@'] = true;
75                 if (frame[spots[i].Bottom][j] != '.')
76                     flag[i][frame[spots[i].Bottom][j]-'@'] = true;
77                     
78             }
79             for (int j = spots[i].Top; j <= spots[i].Bottom; j++)
80             {
81                 if (frame[j][spots[i].Left] != '.')
82                     flag[i][frame[j][spots[i].Left]-'@'] = true;
83                 if (frame[j][spots[i].Right] != '.')
84                     flag[i][frame[j][spots[i].Right]-'@'] = true;
85             }
86         }
87     }
88     for (int i = 1; i <= 26; i++)
89         for (int j = 1; j <= 26; j++)
90             if (i != j && flag[i][j])
91                 D[j]++;
92     CountP = 0;
93     dfs();
94     return 0;
95 }
原文地址:https://www.cnblogs.com/OIerPrime/p/8413079.html