\(Mayan\)游戏

好啊,一年(半年)来的梦魇,终于结束了。

其实我从来没料到整体竟然会如此暴力……做的时候机房里冷得很,感觉晕晕乎乎地做完了,晕晕乎乎地调了好久,晕晕乎乎地听(看了题解的)\(qcr\)给我讲怎么优化代码量,怎么剪枝。

  • 每次搜索要保留本次的状态,这是比较好想的,我也成功的想到了。但是问题是我们不能单纯地用一个二维数组来\(copy\),需要记录步数,不然就会错误\(copy\_back\)。于是最终我们需要一个三维数组来记录。后半段是\(qcr\)告诉我的。

  • 大概就是……我从来没想到\(Mayan\)游戏,会让你每一层\(dfs\)真正地搜全部\(5 \times 7=35\)个块。

  • 还有就是一个小小的剪枝儿。就是由于对于每一个格子,我们考虑它向两边替换,而我们为了避免重复搜索,所以就决定单向搜索,即对于每个块,如果他左边也是一个块,那就不去\(exchange\),只考虑右边;而如果左边是空白格,才\(exchange\)。显然这个剪枝儿的优化性是很显著的。

  • 我一开始写的\(remove()\)、\(down()\)和\(check()\)十分的麻烦——或者说专一?反正之后我懒得调试了,直接听的\(qcr\)的,每次执行这几个函数的时候,直接全屏扫一遍。

  • \(qcr\)给我讲了一个很神的\(down()\)函数。

  • 对于\(exchange\),我们要不断的\(while(remove()) ~;\),因为会不断地有新情况出现。

  • 最后我挂了……几个点来着……忘记了。反正原因是因为,每次\(remove()\)之前应该先\(down()\),然而我并没有\(down()\)干净233

  • 最后再说一个剪枝儿,不是必要性的,但是确实可以加快速度。就是我们再每次遍历\(7 \times 5\)的时候,遇到空白的,不是continue而是break,因为我们\(down\)一定是完备的,所以可以少好几次空遍历。

  • 这是个好题,怎么说呢,折射我代码能力弱的好题。

  • 代码大概\(5k+\)左右

  • 向我自己致敬

// luogu-judger-enable-o2
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream> using namespace std ;
struct D{ int x, y ;} ; stack <D> s ;
struct Ans{ int x, y, d ;} res[100] ; int Remove[50][50] ;
int N, T[30][30], base[4000][10][10], qwq[4000][30], color[30], i, j, t, tot ; inline int qr(){
int res = 0 ; char c = getchar() ;
while (!isdigit(c)) c = getchar() ;
while (isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar() ;
return res ;
}
/*inline void clear(){ while (!s.empty()) s.pop() ; }*/
/*inline void remove(){
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj)
if (T[di][dj] != -1
int cnt = 0 ;
for (int ki = di + 1 ; ki <= 5 && T[ki][dj] == T[di][dj] ; ++ ki) ++ cnt, s.push((D){ki, dj}) ;
for (int ki = di - 1 ; ki >= 1 && T[ki][dj] == T[di][dj] ; -- ki) ++ cnt, s.push((D){ki, dj}) ;
for (int ki = dj + 1 ; ki <= 7 && T[di][ki] == T[di][dj] ; ++ ki) ++ cnt, s.push((D){di, ki}) ;
for (int ki = dj - 1 ; ki >= 1 && T[di][ki] == T[di][dj] ; -- ki) ++ cnt, s.push((D){di, ki}) ;
if (cnt + 1 >= 3){
color[T[di][dj]] -= cnt + 1 ;
while (!s.empty()) T[s.top().x][s.top().y] = -1, s.pop() ;
for (int ki = 1 ; ki <= 5 ; ++ ki)
if (T[ki][dj] == -1){
for (int k = dj ; k <= 7 && (T[ki][k] != -1 || k == dj) ; ++ k) T[ki][k] = T[ki][k + 1] ;
T[ki][0] -- ;
}
}
else clear() ;
}
}*/
/*inline void down(){
for (int di = 1 ; di <= 5 ; ++ di){
int ttt = 0 ;
for (int dj = 1 ; dj <= 7 ; ++ dj)
if (T[di][dj] == -1){
++ ttt ;
for (int k = dj ; k <= 7 ; ++ k) T[di][k] = T[di][k + 1] ;
}
T[di][0] = 7 - ttt ;
}
}*/
inline void down(){//妙啊
int ttt = 0 ;
for(int di = 1 ; di <= 5 ; ++ di){
ttt = 0 ;
for(int dj = 1 ; dj <= 7 ; ++ dj)
if(T[di][dj] == -1) ++ ttt ;
else{
if(! ttt) continue ;
T[di][dj - ttt] = T[di][dj], T[di][dj] = -1 ;
}
// T[di][0] = 7 - ttt ;
}
}
inline bool remove(){ // void -> bool
bool Mark = 0 ;
memset(Remove, 0, sizeof(Remove)) ;
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj){
if (T[di][dj] != -1 && di >= 2 && di <= 4 && T[di][dj] == T[di + 1][dj] && T[di][dj] == T[di - 1][dj]){
Remove[di + 1][dj] = Remove[di - 1][dj] = Remove[di][dj] = 1, Mark = 1 ;
}
if (T[di][dj] != -1 && dj >= 2 && dj <= 6 && T[di][dj] == T[di][dj + 1] && T[di][dj] == T[di][dj - 1]){
Remove[di][dj + 1] = Remove[di][dj - 1] = Remove[di][dj] = 1, Mark = 1 ;
}
}
if (!Mark) return 0 ;
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj)
T[di][dj] = (!Remove[di][dj]) ? T[di][dj] : -1 ;
down() ; return 1 ; }
/*
inline void down(int x, int y, int d){
if (d == 1){
int k, temp = T[x][y] ;
for (k = y ; k <= 7 && T[x][k] != -1 ; ++ k) T[x][k] = T[x][k + 1] ;
for (k = y ; k >= 1 && T[x - 1][k - 1] == -1 ; -- k) ;
T[x - 1][k] = temp ; T[x][0] --, T[x - 1][0] ++ ;
}
else {
int k, temp = T[x][y] ;
for (k = y ; k <= 7 && T[x][k] != -1 ; ++ k) T[x][k] = T[x][k + 1] ;
for (k = y ; k >= 1 &&
T[x + 1][k - 1] == -1 ; -- k) ;
T[x + 1][k] = temp ; T[x][0] --, T[x + 1][0] ++ ;
}
remove() ; return ;
}*/
inline bool judge(){
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj)
if (T[di][dj] != -1) return false ;
return true ;
}
inline void _reset(int x){
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj)
T[di][dj] = base[x][di][dj] ;
}
inline void Prepare(int x){
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj)
base[x][di][dj] = T[di][dj] ;
}
inline void dfs_work(int step){
if (judge()){
for (int di = 1 ; di <= N ; ++ di)
printf("%d %d %d\n", res[di].x, res[di].y, res[di].d) ;
exit(0) ;
}
/*for (int di = 1 ; di <=5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj)
printf("%d%c", T[di][dj], " \n"[dj == 7]) ; */
if (step == N + 1) return ;
Prepare(step) ;
for (int di = 1 ; di <= 5 ; ++ di)
for (int dj = 1 ; dj <= 7 ; ++ dj){
if (T[di][dj] == -1) break ;
if (di > 1 && T[di - 1][dj] == -1){
swap(T[di][dj], T[di - 1][dj]) ; down() ; while (remove()) ;//after exchange, need down
res[step] = (Ans){di - 1, dj - 1, -1} ; dfs_work(step + 1) ; _reset(step) ; res[step] = (Ans){-1, -1, -1} ;
}
if (di < 5 && T[di][dj] != T[di + 1][dj]){
swap(T[di][dj], T[di + 1][dj]) ; down() ; while(remove()) ;
res[step] = (Ans){di - 1, dj - 1 ,1} ; dfs_work(step + 1) ; _reset(step) ; res[step] = (Ans){-1, -1, -1} ;
}
}
}
//problem1 : no reset -> correct
//problem1.5 : the same state -> ?
//problem2 : It's not a good way to search
//ERROR : Why is it broken? How to solve it? int main(){
// freopen("std.out", "w", stdout) ;
cin >> N ; memset(T, -1, sizeof(T)) ;
for (i = 1 ; i <= 5 ; ++ i) T[i][0] = 0 ;
for (i = 1 ; i <= 5 ; ++ i)
while((t = qr()) != 0) T[i][++ T[i][0]] = t ;
dfs_work(1) ; cout << -1 << endl ; return 0 ;
}

随机推荐

  1. setTimeout OR setInterval?

    setTimeout 和setInterval从字面上应该是可以知道其大意的.timeout:延时:interval:间隔: 两者的区别就像是它们自己的英文解释一样:setTimeout是延时执行,并 ...

  2. 构建微服务:快速搭建Spring Boot项目

    Spring Boot简介: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员 ...

  3. linux 光盘yum源搭建

    1.挂载光盘 2.进入 /etc/yum.repos.d 目录,修改其它配置文件后缀名 mv CentOS-Base.repo CentOS-Base.repo.bakmv CentOS-CR.rep ...

  4. 5.Spring MVC 自动装配问题

    一.使用@controller注解,实际上也是在IOC容器中配置了,它的id是类的首字母小写 一.使用@controller注解,实际上也是在IOC容器中配置了,它的id是类的首字母小写 1.如果不使 ...

  5. 使用 Azure CLI 创建和管理 Linux VM

    Azure 虚拟机提供完全可配置的灵活计算环境. 本教程介绍 Azure 虚拟机的基本部署项目,例如选择 VM 大小.选择 VM 映像和部署 VM. 你将学习如何执行以下操作: 创建并连接到 VM 选 ...

  6. 测试SDWebImage淡入淡出效果在UITableView中的重用显示问题

    测试SDWebImage淡入淡出效果在UITableView中的重用显示问题 这个是在上一篇教程的基础上所添加的测试环节! 效果图(从效果图中看是没有任何重用问题的): 源码: ImageCell.h ...

  7. 基于NSString处理文件的高级类

    基于NSString处理文件的高级类 我已经把处理文件的类简化到了变态的程度,如果你还有更简洁的方法,请告知我,谢谢! 使用详情: 源码: // // NSString+File.h // Maste ...

  8. Imagex用法

    imagex用来合并/导出wim映像实例 查看wim中包含的所有单个wim实例信息,注意其中的index是唯一的,用来区分不同的wim,导出的时候也通过该index导出相应的wimimagex /in ...

  9. Element对象 常用属性与常用方法

    常用属性 .children 子元素列表 .childElementCount 子元素数量 .firstElementChild 第一个子元素 .lastElementChild 最后一个子元素 .c ...

  10. 我的Java之旅——答答租车系统的改进

    之前的答答租车系统虽然可以实现项目的要求,但是没有用Java面向对象,今天用面向对象的三大特性封装.继承和多态来改进原来的代码.题目和之前的代码参考上篇博客,这里不再述说. 改进后的代码: Vehic ...