HDOJ 5113 Black And White黑与白

DFS深搜的剪枝。

题目大意,输入一个t(1 <= t < =5000)有t组测试数据,每一组测试数据,第一行输入n,m,k,(0 <=n , m <= 5 , 0 <= k <= 25)第二行 然后k个数,在n * m的矩阵中用着k中颜色填充每个格子,dii中颜色有有k[i]个,共n * m个颜色(注意是k种颜色,共有n * m个颜色),去填充着n*m个格子,每个格子的上向左右填充的颜色不能相同,要求找到一组这样的解,若存在一种解,则输出YES,然后输出每个单元填充的颜色,否则输出NO。若存在多种可行解,输出任意一种即可。

首先你肯定会想到dfs,去尝试用剩下的颜色填充某个格子,若将所有格子都填充完了,并且每个格子的上下左右都不相同,则这是可行解,否则就没有解。但是这一定会超时,你得有优秀的剪枝。最重要的剪枝:当前状态还剩下cnt个格子没有填,某种颜色剩下x个,若某个x大于格子数的一半,即x > (cnt + 1) / 2,则此次尝试一定是不行的。具体请读者画图尝试一下。

下面贴出代码,供大家参考。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n, m, k, arr[26], maze[6][6], color[26];
int dir[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1};
//填x,y这个点,maze里还有cnt个格子未填
bool dfs(int x, int y, int cnt) 
{
    //如果填完了,就true
    if(!cnt) return true; 
    //如果x,y超出范围就返回false
    if(x <= 0 || x > n || y <= 0 || y > m) return false;
    //剪枝:如果剩余的格子数的一半大于某颜色,则这种做法就不行,返回false
    for(int i = 1; i <= k; ++i) 
    {
        if((cnt + 1) / 2 < arr[i]) 
            return false;
    }
    bool vised[26];
    memset(vised, false, sizeof vised);
    //vised记录当前x,y点的上下左右填的颜色,x,y不能填
    for(int i = 0; i < 4; ++i)
    {
        int dx = x + dir[i][0], dy = y + dir[i][1];
        if(dx > 0 && dx <= n && dy > 0 && dy <= m)
            vised[maze[dx][dy]] = true;
    }
    for(int i = 1; i <= k; ++i)//尝试i颜色
    {
        if(arr[i] > 0 && !vised[i])
        {
            arr[i]--;
            maze[x][y] = i; 
            for(int j = 0; j < 4; ++j)
            {
                int dx = x + dir[j][0], dy = y + dir[j][1];
                if(maze[dx][dy] == 0 && dfs(dx, dy, cnt - 1))
                    return true;
            }
            arr[i]++;
            maze[x][y] = 0;
        }
    }
    return false;
}
int main()
{
    int t;
    scanf("%d", &t);
    for(int I = 1; I <= t; ++I)
    {
        memset(maze, 0, sizeof maze);
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= k; ++i)
        {
            scanf("%d", &arr[i]);
            color[i] = arr[i];
        }
        printf("Case #%d:\n", I);
        if(dfs(1, 1, m * n))
        {
            puts("YES");
            for(int i = 1; i <= n; ++i)
            {
                for(int j = 1; j <= m; ++j)
                    printf("%d%c", maze[i][j], j < m? ' ': '\n');
            }
        }
        else 
            puts("NO");
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值