POJ 1128 Frame Stacking(拓扑排序+DFS)

传送门:http://poj.org/problem?id=1128

这题是poj2585加强版,那题是固定图案,而这题是只给你图,求顺序,乍看这题挺难的,但是用2585的思路来处理,两题其实没有什么不同,同样对于每个覆盖的点进行建图,然后建立完一个有向图之后拓扑排序。

这题的重点就是如何确定一个矩阵的位置,我用了map<char,结构体>来记录当前字母的左上角坐标与右下角坐标,那么就能迅速知道每个字母分别覆盖了那些位置,再建图就容易了。

这题还有个坑点,就是如果有多种答案的话,要字典序输出所有解,所以在拓扑的时候要用dfs来写。

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<time.h>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
struct node {
	int xmin, ymin, xmax, ymax;
	node() :xmin(31), ymin(31), xmax(0), ymax(0) {}//构造函数
};
char ans[30];
bool v[30][30];//为了防止对同一个边多次记录,就用邻接矩阵来记录边
int ind[30];
map<char, node> save;
int n, m;
char pic[31][31];
void init()
{
	memset(ind, 0, sizeof(ind));
	memset(v, false, sizeof(v));
	save.clear();
}
void print(int len)
{
	for (int i = 0; i < len; i++)
		printf("%c", ans[i]);
	printf("\n");
}
void topo(int len)
{
	if (len == save.size())
		return print(len);
	int j, k;
	for (j = 0; j < 26; j++)
	{
		if (save.count(j + 'A') && ind[j] == 0)
		{
			ans[len] = j + 'A';
			ind[j] = -1;
			for (k = 0; k < 26; k++)
			{
				if (v[j][k])
					ind[k]--;
			}
			topo(len + 1);
			ind[j] = 0;
			for (k = 0; k < 26; k++)
			{
				if (v[j][k])
					ind[k]++;
			}
		}
	}
}
void build()
{
	int i, j;
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < m; j++)
		{
			if (pic[i][j] == '.')
				continue;
			char now = pic[i][j];
			if (!save.count(now))
				save[now] = node();
			save[now].xmax = max(save[now].xmax, i);//更新左上角与右下角的坐标
			save[now].ymax = max(save[now].ymax, j);
			save[now].xmin = min(save[now].xmin, i);
			save[now].ymin = min(save[now].ymin, j);
		}
	}
	for (map<char, node>::iterator it = save.begin(); it != save.end(); ++it)
	{
		//分别扫描矩形的四个边,如果有其他字母覆盖就建立有向边
		char ch = it->first;
		int x1 = it->second.xmin, y1 = it->second.ymin, x2 = it->second.xmax, y2 = it->second.ymax;
		for (i = x1; i <= x2; i++) if (pic[i][y1] != ch&&!v[ch - 'A'][pic[i][y1] - 'A'])
		{
			v[ch - 'A'][pic[i][y1] - 'A'] = true;
			ind[pic[i][y1] - 'A']++;
		}//y1
		for (i = x1; i <= x2; i++) if (pic[i][y2] != ch&&!v[ch - 'A'][pic[i][y2] - 'A'])
		{
			v[ch - 'A'][pic[i][y2] - 'A'] = true;
			ind[pic[i][y2] - 'A']++;
		}//y2
		for (i = y1; i <= y2; i++) if (pic[x1][i] != ch&&!v[ch - 'A'][pic[x1][i] - 'A'])
		{
			v[ch - 'A'][pic[x1][i] - 'A'] = true;
			ind[pic[x1][i] - 'A']++;
		}//x1
		for (i = y1; i <= y2; i++) if (pic[x2][i] != ch&&!v[ch - 'A'][pic[x2][i] - 'A'])
		{
			v[ch - 'A'][pic[x2][i] - 'A'] = true;
			ind[pic[x2][i] - 'A']++;
		}//x2
	}
}
int main()
{
	//	freopen("D://input.txt", "r", stdin);
	//	freopen("D://output.txt", "w", stdout);
	while (scanf("%d", &n) != EOF)
	{
		scanf("%d", &m);
		int i;
		for (i = 0; i < n; i++)
			scanf("%s", pic[i]);
		init();
		build();
		topo(0);
	}
	//	printf("%.6lf\n", (double)clock() / CLOCKS_PER_SEC);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值