题目描述
看下面的五张 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的版本。
注意几个地方:
- 60~63行的地方,在两个方向上,哪个是i,哪个是j要分清楚。例如:在横向上,i是固定的,要更新的是j。
- 输出注意并没有空格。
- 提交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 }