蓝桥杯C++B组2017决赛铺瓷砖

 参考自蓝桥杯国赛特训营

题意

有一个 3×10 的空地,往里面铺 1×2 的瓷砖,瓷砖有两种颜色(橙色和黄色),并且任意一个 2×2 的空地的瓷砖颜色不能相同,问共有几种贴法。

分析

数据范围很小,只用铺下 3 * 10 / 2 = 15 块瓷砖,所以可以枚举所有瓷砖得摆放方式以及颜色。

用深搜枚举每块瓷砖的颜色,当所有瓷砖都贴完并且合法时,记录答案。

空地状态 g[x] [y]:-1 表示未贴瓷砖,0 表示橙色,1 表示黄色。

当dfs枚举到任意一块没有上色的空地时,有两种贴瓷砖方法(横向和纵向),每种方法有两种颜色

因为只有 30 块瓷砖,每块瓷砖有两种颜色可选,所以最多有 2^30 种情况,刚好可以用一个 int 表达。所以用 status 代表涂色方案,其二进制的第 i 位,代表了第 i 块瓷砖的颜色。之后可以用 set 容器完成去重工作。(个人感悟:对于这种需要存储状态并进行去重的题目,如果每个位置只有两种状态,可以考虑使用一个整数或者一个字符串来代表一个状态, 如果每个位置有多个选择,则只能虑使用一个字符串来代表一个状态)

#include<bits/stdc++.h>

using namespace std;
using LL =long long;

int g[4][11] = {0}; //g[x][y] = -1表示未放置,=0表示放置橙色,=1表示放置黄色

set<string> st; //存放方案数,用于去重


bool check() //对所有放置结果进行检查,判断放置是否合法
{
    for(int i = 1; i <= 2; ++i)
    {
        for(int j = 1; j <= 9; ++j)
        {
            int temp = g[i][j] + g[i+1][j] + g[i][j+1] + g[i+1][j+1];
            if(temp % 4 == 0) //四个格子都放置的是黄色为0,都放置的是橙色为4
                return false; //合法为任意2x2的翻个贴的颜色不一样
        }
    }
    return true;
}

void dfs(int x, int y) //开始从x和y放置瓷砖
{
    if(x > 3 )
    {
        if(check())
		{
            string s = "";
            for(int i =1; i <= 3; ++i)
            {
                for(int j = 1; j <= 10; ++j)
                {
                    s += g[i][j] - '0';
                }
            }
            st.insert(s);
        }
        return ;
    }

    if(g[x][y] == -1)
    {

        if( y < 10 && g[x][y+1] == -1) //横向放置
        {
            for(int i = 0; i <= 1; ++i) //选择颜色
            {
                g[x][y] = g[x][y+1] = i;

                if(y +2 <= 10)
                    dfs(x, y+2); //预剪枝,对于终止条件的处理更方便
                else
                    dfs(x+1, 1);

                //回溯
                g[x][y] = g[x][y+1] = -1;
            }
        }

        if(x < 3 && g[x+1][y] == -1) // 纵向放置
        {

            for(int i = 0; i <=1; ++i) //选择颜色
            {
                g[x][y] = g[x+1][y] = i;

                if( y +1 <= 10 )
                    dfs(x, y+1);
                else
                    dfs(x+1, 1);

                //回溯
                g[x][y] = g[x+1][y] = -1;
            }
        }
    }

    else if( y == 10)
    	dfs(x+1, 1); //到下一行的第一列
    else
        dfs(x, y+1); //同一行的下一列

}


int main()
{
    memset(g, -1, sizeof(g));
    dfs(1,1);

    cout << st.size() << endl;

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值