题目链接

这道题和俄罗斯方块很像

很明显,我们可以看出这是一个dfs,但是,我们需要几条剪枝:

1.如果只剩下1个或2个同样颜色的方块,那么直接退出

2.相同的块不用交换

3.注意优先性,优先左边换右边

但是这题就这么样就完了吗

显然,并没有这么简单:剪枝清楚了,你确定就能写出来吗(这是我写过最长的dfs)

接下来讲一下我的程序架构:

init函数:输入,存储数据

fall函数:模拟方块下落

printans函数:输出答案

clear函数:清除棋盘

isempty函数:判断是否为空

judge函数:剪枝1

dfs函数:搜索

下面是代码,看不懂上面的话,代码里也有注释

 #include <bits/stdc++.h>
using namespace std; const int N = ;
const int M = ; int maxstep, chess[N][M];
int cnt[];
int answer[][]; void init()
{
cin>>maxstep;
for(int i=; i<N; i++)
{
int j=,x;
cin>>x;
while(x!=)
{
chess[i][j]=x;
j++;
cin>>x;
}
}
} void fall() //清除后方块下落
{
for(int i=; i<N; i++)
for(int j=; j<M; j++)
{
if(chess[i][j]!=)
continue;
int k;
for(k=j+; k<M; k++)
if(chess[i][k]!=)
{
swap(chess[i][j],chess[i][k]);
break;
}
if(k==M)
break;
}
} void printans() //输出
{
for(int i=; i<maxstep; i++)
printf("%d %d %d\n",answer[i][],answer[i][],answer[i][]);
return;
} bool clear() //清除棋盘
{
bool empty[N][M];
memset(empty,false,sizeof(empty));
for(int i=; i<N-; i++)
for(int j=; j<M; j++)
if(chess[i][j]!= && chess[i][j]==chess[i+][j]
&& chess[i+][j]==chess[i+][j]) {
empty[i][j]=empty[i+][j]=empty[i+][j]=true;
} for(int i=; i<N; i++)
for(int j=; j<M-; j++)
if(chess[i][j]!= && chess[i][j]==chess[i][j+]
&& chess[i][j+]==chess[i][j+]) {
empty[i][j]=empty[i][j+]=empty[i][j+]=true;
} bool res=false;
for(int i=; i<N; i++)
for(int j=; j<M; j++)
if(empty[i][j])
{
chess[i][j]=;
res=true;
}
return res;
} bool isempty() // 判断棋盘是否为空
{
for(int i=; i<N; i++)
for(int j=; j<M; j++)
if(chess[i][j]!=)
return false;
return true;
} bool judge() //判断是否有一种颜色的块数量为1或2
{
memset(cnt,,sizeof(cnt));
for(int i=; i<N; i++)
for(int j=; j<M; j++)
cnt[chess[i][j]]++;
for(int i=; i<=; i++)
if(cnt[i]==||cnt[i]==)
return false;
return true;
} bool dfs(int step) //搜索
{
if(isempty()) //发现一组解
{
printans();
return true;
}
if(step>=maxstep || !judge()) //剪枝与结束条件
return false; int now[N][M]; // 记录当前状态,回溯时候用
for(int i=; i<N; i++) //复制棋盘
for(int j=; j<M; j++)
now[i][j]=chess[i][j]; for(int i=; i<N; i++)
for(int j=; j<M; j++) //枚举每一个方块
{
//右移
if(i!=N- && chess[i][j]!= && chess[i][j]!=chess[i+][j])
{
swap(chess[i][j], chess[i+][j]);
answer[step][]=i;
answer[step][]=j;
answer[step][]=;
fall();
while(clear())
fall();
if(dfs(step+))
return true;
} for(int k1=; k1<N; k1++)
for(int k2=; k2<M; k2++)
chess[k1][k2]=now[k1][k2]; //左移
if(i!= && chess[i][j]!= && chess[i-][j]==)
{
swap(chess[i][j], chess[i-][j]);
answer[step][]=i;
answer[step][]=j;
answer[step][]=-;
fall();
while(clear())
fall();
if(dfs(step+))
return true;
} for(int k1=; k1<N; k1++)
for(int k2=; k2<M; k2++)
chess[k1][k2]=now[k1][k2];
}
return false;
} /*
搜索+剪枝
剪枝原则:
1,交换两个相同颜色的块没有意义。
2,如果一种颜色的块数量为1或2,则当前局面无解。
3,因为要求字典序最小的解,所以一个块仅当左边为空时尝试左移
(若左面有方块,那么在搜i-1列时将其右移,和在i列时左移是等效的,故可以剪枝)
*/
int main()
{
ios::sync_with_stdio(false);
cin.tie(); init();
if(!dfs())
cout<<-<<endl;
return ;
}

补充:说到俄罗斯方块,我又想起来USACO的这道题,有兴趣的同学可以去做做

洛古 P1312 Mayan游戏(dfs+剪枝)的更多相关文章

  1. 洛谷P1312 Mayan游戏

    P1312 Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他 ...

  2. [NOIP2011] 提高组 洛谷P1312 Mayan游戏

    题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...

  3. 洛谷 P1312 Mayan游戏

    题解:搜索+模拟 剪枝: 最优性剪枝:x从小到大,y从小到大,第一次搜到的就是字典序最小 的最优解. 最优性剪枝:把一个格子和左边格子交换,和左边格子和右边格 子交换是等价的,显然让左边格子和右边交换 ...

  4. Luogu P1312 Mayan游戏(搜索)

    P1312 Mayan游戏 题意 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个\(7\)行\(\times 5\)列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必 ...

  5. [题目] Luogu P1312 Mayan游戏

    题面 题目描述 $ Mayan puzzle $是最近流行起来的一个游戏.游戏界面是一个 \(7行 \times 5列\)的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放 ...

  6. 洛谷 1312 Mayan游戏——暴搜+剪枝

    题目:https://www.luogu.org/problemnew/show/P1312 自己写了很久.又T又WA的. 发现对题理解有误.改完后应该只有T了,但还是T的. 自己写了许多剪枝,很鸡肋 ...

  7. P1312 Mayan游戏

    题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...

  8. [luogu P1312]Mayan游戏

    其实就是一道锻炼码力的简单题-- 看到题目中的\(0<x\leqslant 5\)也就知道是爆搜了吧( 我们仿照写游戏的方法多写几个函数,能够有效降低错误率(确信 我们写出大致的搜索流程来: 如 ...

  9. [洛谷P1731][NOI1999]生日蛋糕(dfs)(剪枝)

    典型的深搜+剪枝策略 我们采用可行性剪枝.上下界剪枝.优化搜索顺序剪枝.最优性剪枝的方面来帮助我们进行剪枝. 也许有人还不知道剪枝,那我就弱弱地为大家补习一下吧qwq: .优化搜索顺序: 在一些搜索问 ...

随机推荐

  1. Python-删除多级目录

    def rmdirs(top): for root, dirs, files in os.walk(top, topdown=False): # 先删除文件 for name in files: os ...

  2. 使用Commons Logging

    Commons Logging 和Java标准库提供的日志不同,Commons Logging是一个第三方日志库,它是由Apache创建的日志模块,需要导入commons-logging-1.2.ja ...

  3. 通过virt-manager给Windowsxp系统配置virtio驱动

    在虚拟机的detail上添加一个硬件设备. 下载virtio.iso文件,我使用的版本126,具体的virtio驱动放到了10.2上的itest的目录中,使用可以找. 在配置中,添加virtio硬盘. ...

  4. Docker快速安装kafka

    Docker快速安装kafka | 沈健的技术博客 盒子 盒子 博客 分类 标签 友链 搜索 文章目录 同样基于docker-compose安装,Docker快速部署nginx中有讲到,不在重述 1. ...

  5. CC03 iOS推送机制浅析

    • ios推送机制 可以通俗的把APNS理解为iOS系统为每个app提供的长连接通道 苹果限制了每个app在后台存活的时间,最重要的目的是为了省电,其次优化内存这些.如果彻彻底底的将app杀死了,服务 ...

  6. Archlinux 自动挂载移动硬盘,开机自动启动smb服务

    Archlinux + Raspberry 打造NAS: samba篇 树莓派自动挂载硬盘,并开启smb服务. 开机自动挂在移动硬盘ntfs 安装ntfs-3g sudo pacman -S ntfs ...

  7. Magic Methods 5

    描述符 : 将某种特殊类型的类的实例指派给另一个类的属性. 特殊类型为以下方法的1-3个 : __get__(self, instance, owner):用于访问属性,它返回属性的值 __set__ ...

  8. Daily Practice 2016-09-20

    算法 回文(Palindrome)数字:判断一个数字是不是回文数字,不能使用另外的空间. 提示: 负数可以是回文数字吗? 如果转为字符串需要新分配空间 你也许想到了反转数字,但反转数字可能溢出,怎样处 ...

  9. 利用 Rize 来进行 UI 测试或 E2E 测试

    之前我曾经在<Rize - 一个可以让你简单.优雅地使用 puppeteer 的 Node.js 库>一文简单介绍过 Rize 这个库.当时仅仅是介绍这个库本身,关于如何使用,我没有给太多 ...

  10. spring——AOP原理及源码(四)

    前情回顾: 上文我们一路分析了从容器创建开始直到我们的AOP注解导入的核心组件AnnotationAwareAspectJAutoProxyCreator执行postProcessBeforeInst ...