题面

过长已遮挡

题意

体面已经陈述题意(这题没有考语文阅读理解)

题解

** 我还记得我曾经给自己找的锅,给某些人讲课的时候说过一句话:体面越长的题,越简单。** 这句话没有错,我会用接下来解决这道题的思路过程,来证明这句话。

  1. 首先我们知道存在这么几种操作:

    a. 交换操作

    b. 下沉操作

    c. 消除操作

    d. 搜索操作

    e. 玩完判断

    f. 拷贝操作(回溯)

  2. 这时候可以看得出来这里面除了搜索操作,剩余的操作都是模拟,我们只需要分出多个函数进行模拟就好了。

  3. 但是思路就是如此简单的一道题我却调了一个下午。(代码量是真的大,不压横150+行代码),还是我太菜了。

  4. 因为数据量非常小,不用怎么优化也能过,但是写代码的时候一定要小心。


下沉操作

每次交换完 or 消除完都要进行的操作。

  1. 遍历图上的每一个点,如果有颜色,判断下面是否还有颜色

  2. 没有颜色:立一个\(flag\),向下一直找到呢个有颜色的点,然后利用\(flag\)下沉到有显色点的上方。

  3. 有颜色:跳出当前列。

void update()
{
for(int i = 1;i <= 5;++i)
{
int flag = 0;
for(int j = 1;j <= 7;++j)
{
if(!mapp[i][j]) flag++;
else
{
if(!flag) continue;
mapp[i][j - flag] = mapp[i][j];
mapp[i][j] = 0;
}
}
}
}

消除操作

每次下沉完都要进行的操作。根据题意会有三种情况:只有横着的三个;只有竖着的三个;横着三个交叉在竖着三个之间;横着三个和竖着三个同时出现但不相交。

但是我们可以把它们归纳到一种情况,就是只要有三个连续相同的出现就加到桶里面,然后再把桶扫一遍,全部染回没有颜色,这样就消除了。

这里呢还可以加一个小优化,立一个\(flag\)。因为根据题意,消除完还要进行下沉操作,但是如果我们没有可消除,就浪费了下沉的一些时间。

代码操作非常简单,只要根据上面的分析进行模拟就好了。

bool reover()
{
bool flag = 1;
for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
if(i-1 >= 1 && i+1 <= 5 && mapp[i][j] && mapp[i][j] == mapp[i-1][j] && mapp[i][j] == mapp[i+1][j])
{
tong[i][j] = 1;
tong[i-1][j] = 1;
tong[i+1][j] = 1;
flag = 0;
}
if(j-1 >= 1 && j+1 <= 7 && mapp[i][j] && mapp[i][j] == mapp[i][j-1] && mapp[i][j] == mapp[i][j+1])
{
tong[i][j] = 1;
tong[i][j-1] = 1;
tong[i][j+1] = 1;
flag = 0;
}
} if(flag) return 0; for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
if(tong[i][j])
{
mapp[i][j] = 0;
tong[i][j] = 0;
}
} return 1;
}

交换操作

根据题意可得,交换的流程是这样的:

交换两个点颜色 -> 下沉操作 -> 消除操作 -> 下沉操作 -> 消除操作

一直到不能再消除,交换结束。

void move(int i,int j,int flag)
{
swap(mapp[i][j],mapp[i+flag][j]);
update();
while(reover()) update();
}

玩完判断

只需要扫描最后一层,如果还有颜色,肯定是没有玩完。

bool gameover()
{
for(int i = 1;i <= 5;++i)
if(mapp[i][1]) return 0; return 1;
}

拷贝操作(回溯)

留一个备份是为了方便我们搜索完一轮后,返回时恢复初值。

代码非常的简单容易理解。

void move(int i,int j,int flag)
{
swap(mapp[i][j],mapp[i+flag][j]);
update();
while(reover()) update();
}

搜索操作

这一块是最容易出错的,但是细心一些还是能过得,毕竟这个搜索也不需要优化。

  1. 如果已经玩完了,直接输出答案,结束程序。

  2. 如果搜索长度大于等于n了,不用再往后面搜了。

  3. 留一个备份,方便一会回溯。

  4. 1和2都不成立,就继续搜。分两种情况,左搜和右搜。

    a. 左搜:首先左边界肯定要大于等于1,左边的方块还没有颜色。

    b. 右搜:首先右边界肯定要小于等于5,相邻两颜色还不能相同。

  5. 搜完一定要记得回溯

void dfs(int x)
{
if(gameover())
{
for(int i = 1;i <= n;++i)
{
if(i != 1) cout << endl;
cout << ans[i][1] <<" "<< ans[i][2] <<" "<< ans[i][3];
}
exit(0);
} if(x == n+1) return; copy(x); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
if(mapp[i][j])
{
if(i-1 >= 1 && mapp[i-1][j] == 0)
{
move(i,j,-1);
ans[x][1] = i-1;
ans[x][2] = j-1;
ans[x][3] = -1; dfs(x+1); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
mapp[i][j] = last[x][i][j]; ans[x][1] = 0;
ans[x][2] = 0;
ans[x][3] = 0;
} if(i+1 <= 5 && mapp[i][j] != mapp[i+1][j])
{
move(i,j,1);
ans[x][1] = i-1;
ans[x][2] = j-1;
ans[x][3] = 1; dfs(x+1); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
mapp[i][j] = last[x][i][j]; ans[x][1] = 0;
ans[x][2] = 0;
ans[x][3] = 0;
}
}
}
}

代码

这道题的代码挺考察耐心的,我调了两个小时才调出来AC100分的结果。

#include <bits/stdc++.h>
using namespace std; #define il inline int n;
int mapp[10][10],ans[10][10],last[10][10][10],tong[10][10]; il int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
} il bool reover()
{
bool flag = 1;
for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
if(i-1 >= 1 && i+1 <= 5 && mapp[i][j] && mapp[i][j] == mapp[i-1][j] && mapp[i][j] == mapp[i+1][j])
{
tong[i][j] = 1;
tong[i-1][j] = 1;
tong[i+1][j] = 1;
flag = 0;
}
if(j-1 >= 1 && j+1 <= 7 && mapp[i][j] && mapp[i][j] == mapp[i][j-1] && mapp[i][j] == mapp[i][j+1])
{
tong[i][j] = 1;
tong[i][j-1] = 1;
tong[i][j+1] = 1;
flag = 0;
}
} if(flag) return 0; for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
if(tong[i][j])
{
mapp[i][j] = 0;
tong[i][j] = 0;
}
} return 1;
} il bool gameover()
{
for(int i = 1;i <= 5;++i)
if(mapp[i][1]) return 0; return 1;
} il void copy (int x)
{
for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
last[x][i][j] = mapp[i][j];
}
} il void update()
{
for(int i = 1;i <= 5;++i)
{
int flag = 0;
for(int j = 1;j <= 7;++j)
{
if(!mapp[i][j]) flag++;
else
{
if(!flag) continue;
mapp[i][j - flag] = mapp[i][j];
mapp[i][j] = 0;
}
}
}
} il void move(int i,int j,int flag)
{
swap(mapp[i][j],mapp[i+flag][j]);
update();
while(reover()) update();
} void dfs(int x)
{
if(gameover())
{
for(int i = 1;i <= n;++i)
{
if(i != 1) cout << endl;
cout << ans[i][1] <<" "<< ans[i][2] <<" "<< ans[i][3];
}
exit(0);
} if(x == n+1) return; copy(x); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
{
if(mapp[i][j])
{
if(i-1 >= 1 && mapp[i-1][j] == 0)
{
move(i,j,-1);
ans[x][1] = i-1;
ans[x][2] = j-1;
ans[x][3] = -1; dfs(x+1); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
mapp[i][j] = last[x][i][j]; ans[x][1] = 0;
ans[x][2] = 0;
ans[x][3] = 0;
} if(i+1 <= 5 && mapp[i][j] != mapp[i+1][j])
{
move(i,j,1);
ans[x][1] = i-1;
ans[x][2] = j-1;
ans[x][3] = 1; dfs(x+1); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 7;++j)
mapp[i][j] = last[x][i][j]; ans[x][1] = 0;
ans[x][2] = 0;
ans[x][3] = 0;
}
}
}
} int main(int argc, char const *argv[])
{
n = read(); for(int i = 1;i <= 5;++i)
for(int j = 1;j <= 8;++j)
{
int x = read();
if(x == 0) break;
mapp[i][j] = x;
} dfs(1); printf("-1\n"); return 0;
}

题解 P1312 【Mayan游戏】的更多相关文章

  1. 洛谷P1312 Mayan游戏

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

  2. Luogu P1312 Mayan游戏(搜索)

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

  3. [题目] Luogu P1312 Mayan游戏

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

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

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

  5. P1312 Mayan游戏

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

  6. 洛谷 P1312 Mayan游戏

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

  7. [luogu P1312]Mayan游戏

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

  8. 洛古 P1312 Mayan游戏(dfs+剪枝)

    题目链接 这道题和俄罗斯方块很像 很明显,我们可以看出这是一个dfs,但是,我们需要几条剪枝: 1.如果只剩下1个或2个同样颜色的方块,那么直接退出 2.相同的块不用交换 3.注意优先性,优先左边换右 ...

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

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

  10. luoguP1312 Mayan游戏 题解(NOIP2011)

    luoguP1312 Mayan游戏 题目 #include<bits/stdc++.h> #define ll long long #define rg register #define ...

随机推荐

  1. MWeb 生成静态网站&博客

    MWeb 生成静态网站 & 博客 MWeb 的静态网站分类 在 MWeb 的文档库中,有两种分类,一种是普通分类,另一种就是静态网站分类了.你可以直接新增一个静态网站分类,也可以在普通分类的顶 ...

  2. ES 记录之如何创建一个索引映射,以及一些设置

    ElasticSearch 系列文章 1 ES 入门之一 安装ElasticSearcha 2 ES 记录之如何创建一个索引映射 3 ElasticSearch 学习记录之Text keyword 两 ...

  3. Nodejs编写复制文件及文件夹命令

    github地址 use npm i fuzhi -g 复制文件 fuzhi a.js b.js 复制文件夹 fuzhi dirA dirB Wiki 创建一个node命令的两个关键点 1.在pack ...

  4. .8-浅析express源码之请求处理流程(1)

    这一节就讲从一个请求到来,express内部是如何将其转交给合适的路由,路由又是如何调用中间件的. 以express-generator为例,关键代码如下: // app.js app.use('/' ...

  5. [转]分布式中Redis实现Session终结篇

    本文转自:http://www.cnblogs.com/yanweidie/p/4763556.html 上一篇使用Redis实现Session共享方式虽然可行,但是实际操作起来却很麻烦,现有代码已经 ...

  6. MVC使用jQuery.ajax()删除数据

    jQuery.ajax()可以简写为$.ajax().以前有写过MVC删除的实现,如<MVC实现删除数据库记录> http://www.cnblogs.com/insus/p/336804 ...

  7. Direct2D教程I——简介及首个例子

    在博客园里,系统的Direct2D的教程比较少,只有“万一”写了一个关于Direct2D的系列(Delphi 2009).于是,仿照其系列,写一个在VS下的Direct2D系列教程. 博客园中的高手还 ...

  8. Java - "JUC" CountDownLatch源码分析

    Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例 CountDownLatch简介 CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前 ...

  9. Linux常用基本命令( touch )

    touch命令: 作用:创建空文件,或者改变文件的时间戳属性 格式: touch [option] [file] 1,同时创建一个或者多个空文件 ghostwu@dev:~/linux/mkdir$ ...

  10. vue.js自定义指令详解

    写在文本前:相信在做vue的项目,你肯定接触了指令,我们常用vue内置的一些指令,比如v-model,v-text,v-if,v-show等等,但是这些内置指令不在本文的讲解范畴,本文想说的是其自定义 ...