题目大意:
现有如下5个框架:
其中每个框架由大写字母组成,只有边中间镂空,先将框架按照12345的顺序层层覆盖1在最底部5在最顶部,得到下图:
现在从底到顶得到序列EDABC,现给定一副框架之间相互覆盖的图,图中保证:
1. 一个框架必定只由一种字母组成,不会出现同一个字母的多个框架,并且每个框架的边长至少大于3;
2. 每个框架都能看到其4个角;
现有多个测例(测例以EOF结束),每个测例中都会给出图的规模h×w(h, w ≤ 30,行数为h,列数为w),接下来给出该图的矩阵,对于每个测例都要求输出从底到顶的序列,如果存在多个序列(有可能有两个部分没有相互覆盖),则按照字典序升序输出所有可能序列,测例之间不要用空行隔开。
注释代码:
/*
* Problem ID : POJ 1128 Frame Stacking
* Author : Lirx.t.Una
* Language : C++
* Run Time : 0 ms
* Run Memory : 164 KB
*/
#include <iostream>
#include <cstring>
#include <cstdio>
//坐标的最大值(下标从0计,29最大)
#define INF 30
//26个字母
#define N 26
//框架的最大宽度
#define MAXW 30
using namespace std;
char m[MAXW][MAXW + 1];//存放框架信息,以%s形式逐行读入
//记录每种字母的最大和最小横坐标以确定其左上角和右下角
//下标从0 ~ 25表示A ~ Z
//注意x轴朝下,y轴朝右
char x1[MAXW], x2[MAXW];//最小最大纵坐标
char y1[MAXW], y2[MAXW];//最小最大横坐标
//思路:如果B盖在A上面就从A连向B一条边
//本题就转化成了拓扑排序问题了,下标从0 ~ 25表示A ~ Z
bool g[N][N];//表示关系的图
char deg[N];//各点的入度
char path[N + 1];//最终所求序列
int stp;//当前序列的长度,即步数,深搜时更新
int cnt;//总共用到了多少个字母
//由于字母不是前多少个而是随机出现了,因此需要记录总共用到了
//多少个不同的字母
inline int
max( int a, int b ) {
return a > b ? a : b;
}
inline int
min( int a, int b ) {
return a < b ? a : b;
}
void
dfs(void) {//由于要按照字典序升序打印出所有可能因此使用深搜
//每次搜索的方向都是以小字母为先,结果必定是升序的
//由于题目保证一定有解因此不必特判
int u, v;//点
if ( stp == cnt ) {//如果步数已经到达字母个数表示搜索成功
//直接输出即可
path[stp] = '\0';
puts(path);
return ;
}
for ( u = 0; u < N; u++ )//从小到大搜索
if ( !deg[u] ) {//找到一个0入度的点就顺着该点向下纵深
path[stp] = u + 'A';//记录到path中,需要从下标转换到相应的字母
stp++;//步数增加
deg[u]--;//将该点入度减到-1,避免在下一层深搜过程中重复使用该点
for ( v = 0; v < N; v++ )//更新与之相连点的入度
if ( g[u][v] ) deg[v]--;
dfs();//进入下一层
//搜索完毕后还原现场,再测试本层中下一个点
for ( v = 0; v < N; v++ )
if ( g[u][v] ) deg[v]++;
deg[u]++;
stp--;
}
}
int
main() {
int h, w;//框架的高和宽
int i, j, k, c;//计数变量、临时变量
int i1, i2;//存放字母的纵坐标极值
int j1, j2;//存放字母的横坐标极值
while ( ~scanf("%d%d", &h, &w) ) {
//初始化
memset(g, false, sizeof(g));
memset(x1, INF, sizeof(x1));
memset(y1, INF, sizeof(y1));
memset(x2, -1, sizeof(x2));
memset(y2, -1, sizeof(y2));
memset(deg, -1, sizeof(deg));//注意要初始化成-1,因为有些点不用
//如果初始化成0则那些不用的点也会被多算进去
for ( i = 0; i < h; i++ ) scanf("%s", m[i]);//读入框架
for ( k = 0; k < N; k++ )//逐个枚举检测每个字母k: 0 ~ 25 = A ~ Z
for ( i = 0; i < h; i++ )
for ( j = 0; j < w; j++ )
if ( m[i][j] == k + 'A' ) {//获得极值
x1[k] = min( x1[k], i );
x2[k] = max( x2[k], i );
y1[k] = min( y1[k], j );
y2[k] = max( y2[k], j );
}
cnt = 0;//统计多少个字母被用到了
for ( i = 0; i < N; i++ )
if ( x1[i] != INF ) {
cnt++;
deg[i]++;//用到的字母入度置0
}
for ( k = 0; k < N; k++ )//枚举计算出每个字母的坐标极值
if ( x1[k] != INF ) {
i1 = x1[k];
i2 = x2[k];
j1 = y1[k];
j2 = y2[k];
for ( j = j1; j <= j2; j++ ) {
c = m[i1][j] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
c = m[i2][j] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
}
for ( i = i1; i <= i2; i++ ) {
c = m[i][j1] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
c = m[i][j2] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
}
}
stp = 0;//初始化搜索步数
dfs();
}
return 0;
}
无注释代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define INF 30
#define N 26
#define MAXW 30
using namespace std;
char m[MAXW][MAXW + 1];
char x1[MAXW], x2[MAXW];
char y1[MAXW], y2[MAXW];
bool g[N][N];
char deg[N];
char path[N + 1];
int stp;
int cnt;
inline int
max( int a, int b ) {
return a > b ? a : b;
}
inline int
min( int a, int b ) {
return a < b ? a : b;
}
void
dfs(void) {
int u, v;
if ( stp == cnt ) {
path[stp] = '\0';
puts(path);
return ;
}
for ( u = 0; u < N; u++ )
if ( !deg[u] ) {
path[stp] = u + 'A';
stp++;
deg[u]--;
for ( v = 0; v < N; v++ )
if ( g[u][v] ) deg[v]--;
dfs();
for ( v = 0; v < N; v++ )
if ( g[u][v] ) deg[v]++;
deg[u]++;
stp--;
}
}
int
main() {
int h, w;
int i, j, k, c;
int i1, i2;
int j1, j2;
while ( ~scanf("%d%d", &h, &w) ) {
memset(g, false, sizeof(g));
memset(x1, INF, sizeof(x1));
memset(y1, INF, sizeof(y1));
memset(x2, -1, sizeof(x2));
memset(y2, -1, sizeof(y2));
memset(deg, -1, sizeof(deg));
for ( i = 0; i < h; i++ ) scanf("%s", m[i]);
for ( k = 0; k < N; k++ )
for ( i = 0; i < h; i++ )
for ( j = 0; j < w; j++ )
if ( m[i][j] == k + 'A' ) {
x1[k] = min( x1[k], i );
x2[k] = max( x2[k], i );
y1[k] = min( y1[k], j );
y2[k] = max( y2[k], j );
}
cnt = 0;
for ( i = 0; i < N; i++ )
if ( x1[i] != INF ) {
cnt++;
deg[i]++;
}
for ( k = 0; k < N; k++ )
if ( x1[k] != INF ) {
i1 = x1[k];
i2 = x2[k];
j1 = y1[k];
j2 = y2[k];
for ( j = j1; j <= j2; j++ ) {
c = m[i1][j] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
c = m[i2][j] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
}
for ( i = i1; i <= i2; i++ ) {
c = m[i][j1] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
c = m[i][j2] - 'A';
if ( c != k && !g[k][c] ) {
g[k][c] = true;
deg[c]++;
}
}
}
stp = 0;
dfs();
}
return 0;
}