hdu5113 Black And White--DFS & 剪枝

原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=5113


题意:

一个n*m的矩阵,给定n*m个颜色,颜色一共有k种,每种a[ i ]个,现在要你把所有颜色填到矩阵中,要求相邻(也就是上下左右)颜色不重复。

很明显的深搜,不过这深搜是一个一个去找,每个必须配颜色,所以对于当前点,查找的方向就是两个,一是当前行,列加1,二是走至行尾,开始走下一行的第一列。所以这题不用开数组dir保存四个方向。


另外剪枝,如果走到当前点,发现还没有填充的点的一半比剩下颜色的最大值还小,那肯定不可以的,读者可以画图看一下。另外贴下AC代码:


#define _CRT_SECURE_NO_DEPRECATE 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

int p[6][6];
int a[30];
int t, n, m, k;
int flag;

void dfs(int x, int y, int color)
{
	for (int i = 1; i <= k; i++)//剪枝
		if (a[i] > ((n - x)*m + m - y + 1) / 2)
			return;

	p[x][y] = color;
	if (x == n&&y == m)
	{
		flag = 1;
		return;
	}

	if (y + 1 <= m)//往前走一步,不越界的话
	{
		int xx = x;
		int yy = y + 1;
		int i;
		
		for (i = 1; i <= k; i++)
		{
			if (a[i] && i != p[xx][yy - 1] && i != p[xx - 1][yy])//颜色还有,左边,上边颜色不重复
			{
				a[i] --;
				dfs(xx, yy, i);
				if (flag == 1)
					return;
				a[i]++;
			}
		}
	}
	else if (x + 1 <= n)
	{
		int xx = x + 1;
		int yy = 1;
		int i;
		
		for (i = 1; i <= k; i++)
		{
			if (a[i] && i != p[xx - 1][yy])//颜色还有,左边,上边颜色不重复
			{
				a[i] --;
				dfs(xx, yy, i);
				if (flag == 1)
					return;
				a[i]++;
			}
		}
	}
}

int main()
{
	scanf("%d", &t);
	for (int cas = 1; cas <= t; cas++)
	{
		scanf("%d%d%d", &n, &m, &k);
		for (int i = 1; i <= k; i++)
			scanf("%d", &a[i]);

		flag = 0;
		memset(p, 0, sizeof(p));

		for (int i = 1; i <= k; i++)
		{
			a[i]--;
			dfs(1, 1, i);
			if (flag == 1)
				break;
			a[i]++;
		}

		if (flag)
		{
			printf("Case #%d:\nYES\n", cas);
			for (int i = 1; i <= n; i++)
			{
				for (int j = 1; j <= m; j++)
				{
					if (j == m)
						printf("%d\n", p[i][j]);
					else
						printf("%d ", p[i][j]);
				}
			}
		}
		else
			printf("Case #%d:\nNO\n", cas);
	}
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值