题目链接: 674. 超级2048 - AcWing题库

题目描述:

2048 是一个著名的单人游戏,其目标是在网格上滑动图块以组合它们并创建数字为2048的图块。

2048 在一个简单的4×4 网格上进行游戏,其中有一些图块,玩家可以对它们进行移动。

每一步操作,玩家可以选择向左,向右,向上和向下 4 个方向去移动所有图块。

如果两个包含数字相同的图块在移动时发生碰撞,则它们将合并为一个图块,该图块上的数值为两个图块的数字之和。

在一次操作中,一个新创建的图块不能再次参与合并,并且图块们总是优先沿着移动方向与其旁边的图块进行合并。

例如,如果三个 2 在一行构成 2 2 2,这时玩家选择向左移动,则它将变为 4 2 0,最左边的两个 22 会被合并。

上图显示了当玩家将所有图块“右移”时 4×4 网格的变化情况。

爱丽丝和鲍勃非常喜爱这个游戏。

但是几轮后,他们觉得网格的尺寸太小了并不刺激,所以决定将网格的尺寸扩大到 N×NN×N,他们称之为“超级 2048”游戏。

但是难度的激增让他们无法驾驭这个游戏。

他们要求你编写一个程序来帮助他们弄清楚在所有图块沿着某个特定方向移动后网格的样子。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 N 和一个字符串 DIR,其中 NN 表示网格的尺寸,DIR 表示图块的移动方向,DIR 将会是以下四个字符串中的一个:leftrightupdown

接下来 N 行,每行包含 N 个整数,用来描述网格的初始状态,每个整数表示网格中一个图块的值,如果为 0 则表示该位置是空的。

输出格式

对于每组测试数据,第一行输出 Case #x:,其中 x 为组别编号(从 1 开始)。

然后输出 N 行,每行 N 个空格隔开的整数,表示图块移动后网格的样子。

数据范围

1≤T≤100
1≤N≤20
网格中的每个数字都是 0 或 2 到 1024 之间的 2 的整数次幂,包括 2 和 1024。

输入样例:

3
4 right
2 0 2 4
2 0 4 2
2 2 4 8
2 2 4 4
10 up
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 right
2 2 2
4 4 4
8 8 8

输出样例:

Case #1:
0 0 4 4
0 2 4 2
0 4 4 8
0 0 4 8
Case #2:
4 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Case #3:
0 2 4
0 4 8
0 8 16

思想

(此距离为右向移动,图片丑请勿怪):

定义start下标指针,指向遍历的起点,idx初始值为遍历的开始起点也就是start的初始值

由start开始遍历,由新的 k 下标指针(start - 1),进行遍历到start当前位置之后(此“之后为遍历的下一个位置的意思),当遇到不为0的时候停止。查看当前 k 和 start指向值的关系,如果是相同的那么也就发生了“碰撞”行为(2048游戏中移动时相邻的相同值会被合并,以下我简称”碰撞“),那么将 idx 指向的下标位置的值赋值为 当前 start 值指向的两倍、如果没有发生”碰撞“,那么将 idx 指向的下标位置的值赋值为 当前 start 值,随后,将 start 的下标位置挪动到当前 k 下标所指向的位置。此图为第一次遍历之后所产生的情况。

当最后一次遍历之后会是下图的情况

完成之后,在以idx为遍历起点,将之后的值初始化为‘空’(0值),即可

先是最为初始化的思想,将上下左右的移动,写出为四个函数:

之后将是把四个情况融合在一起:

#include <bits/stdc++.h>
using namespace std;const int N = 30;
int arr[N][N];void getUp(int n);
void getDown(int n);
void getLeft(int n);
void getRight(int n);int main() {int t;cin >> t;for (int t1 = 1;t1 <= t;t1 ++) {int n;string str;cin >> n >> str;for (int i = 0;i < n;i ++) for (int j = 0;j < n;j ++) cin >> arr[i][j];if (str == "up") getUp(n);if (str == "down") getDown(n);if (str == "left") getLeft(n);if (str == "right") getRight(n);cout << "Case #" << t1 << ":" << endl;for (int i = 0;i < n;i ++) {for (int j = 0;j < n;j ++) cout << arr[i][j] << ' ';cout << endl;}}return 0;
}void getUp(int n){for (int i = 0;i < n;i ++) { // 遍历每一列int idx = 0;for (int j = 0;j < n;j ++) {if (arr[j][i] == 0) continue; // j => 行号int k = j + 1;while (k < n && arr[k][i] == 0) k ++;if (k < n && arr[j][i] == arr[k][i]) {arr[idx ++][i] = 2 * arr[j][i];j = k;}else arr[idx ++][i] = arr[j][i];}for (int j = idx;j < n;j ++) arr[j][i] = 0;}
}void getDown(int n){for (int i = 0;i < n;i ++) { // 遍历每一列int idx = n - 1;for (int j = n - 1;j >= 0;j --) {if (arr[j][i] == 0) continue; // j => 行号int k = j - 1;while (k >= 0 && arr[k][i] == 0) k --;if (k >= 0 && arr[j][i] == arr[k][i]) {arr[idx --][i] = 2 * arr[j][i];j = k;}else arr[idx --][i] = arr[j][i];}for (int j = idx;j >= 0;j --) arr[j][i] = 0;}
}void getLeft(int n){for (int i = 0;i < n;i ++) {int idx = 0;for (int j = 0;j < n;j ++) {if (arr[i][j] == 0) continue;int k = j + 1;while (k < n && arr[i][k] == 0) k ++;if (k < n && arr[i][j] == arr[i][k]) {arr[i][idx ++] = 2 * arr[i][k];j = k;}else arr[i][idx ++] = arr[i][j];}for (int j = idx;j < n;j ++) arr[i][j] = 0;}
}void getRight(int n){for (int i = 0;i < n;i ++) {int idx = n - 1;for (int j = idx;j >= 0;j --) {if (arr[i][j] == 0) continue;int k = j - 1;while (k >= 0 && arr[i][k] == 0) k --;if (k >= 0 && arr[i][j] == arr[i][k]) {arr[i][idx --] = 2 * arr[i][k];j = k;}else arr[i][idx --] = arr[i][j];}for (int j = idx;j >= 0;j --) arr[i][j] = 0;}
}

将四种情况写到了一种函数当中:

#include <bits/stdc++.h>
using namespace std;const int N = 30;
int arr[N][N];void check(int n, int fleft, int fright);int main() {int t;cin >> t;for (int t1 = 1;t1 <= t;t1 ++) {int n;string str;cin >> n >> str;for (int i = 0;i < n;i ++) for (int j = 0;j < n;j ++) cin >> arr[i][j];if (str == "up") check(n, 0, 1);if (str == "down") check(n, 0, -1);if (str == "left") check(n, 1, 0);if (str == "right") check(n, -1, 0);cout << "Case #" << t1 << ":" << endl;for (int i = 0;i < n;i ++) {for (int j = 0;j < n;j ++) cout << arr[i][j] << ' ';cout << endl;}}return 0;
}/* 解决2048游戏中横竖向移动问题, 其中arr是存储为int类型的2048图@parma n 当前移动位置的长度, 默认区间在[0, n-1]中@parma frow 当前是否横向移动, frow > 0 => 向右移动, frow < 0 => 向左移动, frow == 0 不移动@parma fcol 当前是否纵向移动, fcol > 0 => 向下移动, fcol < 0 => 向上移动, fcol == 0 不移动
*/
void check(int n, int frow, int fcol) {// 判断当前是否出现了不移动,或者横纵向同时移动的状态,此为错误的操作if ((frow == 0 && fcol == 0) || (frow != 0 && fcol != 0)) return;int start, flag; // 定义开始遍历的起点下标, 遍历的方向// 当flag = 1时候,即为从左往右(从上往下)开始遍历, 为-1的时候就相反// ----------------相应的start起点下标也就是0,----------------n - 1if (frow > 0 || fcol > 0) start = 0, flag = 1;else start = n - 1, flag = -1;for (int i = 0;i < n;i ++) { // 开始横线或纵向遍历//定义一个和start同向且初始值相同的下标指针,当2048开始移动时发生碰撞产生改变时//存储点的下标位置int idx = start; //开始纵向或横线遍历,这取决外层循环的涵义for (int j = start;j >= 0 && j < n;j += flag) {//当frow != 0,表示现在外层循环是一个纵向遍历,内层循环是一个横向遍历…………//即在遍历过程中遇到0,也就是2048游戏中的空位的时候,进行一个跳过if ((frow != 0 && arr[i][j] == 0) || (fcol != 0 && arr[j][i] == 0)) continue;//定义k指针为当前j指针的后一个(此前并非为j + 1,而是遍历元素的后一个,与遍历方向有关int k = j + flag;//用于跳过j指针后存在的'空'(0值),直到找到相同值或不同值if (fcol != 0) while (k >= 0 && k < n && arr[k][i] == 0) k += flag;//纵向遍历else while (k >= 0 && k < n && arr[i][k] == 0) k += flag;//横向遍历//找到需要处理的值之后,判断横纵向遍历if (frow == 0) {//如果当前 k 指针没有越界行为,并且与 j 指针指向的值相同,即发生碰撞if (k >= 0 && k < n && arr[j][i] == arr[k][i]) arr[idx][i] = 2 * arr[j][i], j = k;else arr[idx][i] = arr[j][i];// 有不同值则赋值到存储点}else {if (k >= 0 && k < n && arr[i][j] == arr[i][k]) arr[i][idx] = 2 * arr[i][j], j = k;else arr[i][idx] = arr[i][j];}//处理完一次碰撞或没有碰撞之后,存储点的位置也要跟随start遍历的方向挪动idx += flag;}//移动处理完之后,剩余的部分理应为'空'(0值)for (int j = idx;j >= 0 && j < n;j += flag)//判断横纵向遍历,进行赋值frow == 0 ? arr[j][i] = 0 : arr[i][j] = 0;}
}

AcWing 674.超级2048相关推荐

  1. 带你用Python制作超级经典的2048游戏(文末赠书)

    名字:阿玥的小东东 学习:Python.C/C++ 主页链接:阿玥的小东东的博客_CSDN博客-python&&c++高级知识,过年必备,C/C++知识讲解领域博主 目录 2048游戏 ...

  2. AcWing 2048. 干草

    奶牛们又来捣乱了! 农夫约翰精心整理的 NN 堆干草,每堆干草的高度相同. 但是,奶牛们趁着他不注意在干草堆之间移动了一些干草捆,使得各个干草堆的高度可能不再相同了. 给定所有干草堆的新高度,请帮助约 ...

  3. 解题报告:POJ - 1062 昂贵的聘礼(最短路、超级源点)

    整理的算法模板合集: ACM模板 AcWing 903. 昂贵的聘礼 [思路] 由于本题只有终点,没有起点,所以我们建一个超级源点S=0S = 0S=0 ,源点与各各点的权值就是他们的价格 如下图所示 ...

  4. 我的名片能运行Linux和Python,还能玩2048小游戏,成本只要20元

    晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI 猜猜它是什么?印着姓名.职位和邮箱,看起来是个名片.可是右下角有芯片,看起来又像是个PCB电路板. 其实它是一台超迷你的ARM计算机,不仅 ...

  5. 算法提高课-图论-差分约束- AcWing 1169. 糖果:spfa求单源最短路、差分约束

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析: 差分约束系统 差分约束系统是一种特殊的N元一次不等式组.它包含N个变量X1,...,XnX_1,...,X_nX1​,...,Xn​ ...

  6. linux下Oracle 10g安装(超级详细图解教程)

    linux下Oracle 10g安装(超级详细图解教程) 一,基本配置: 1.以root登录,挂载linux iso文件 [root@oracle ~]# hostnameoracle.junjie. ...

  7. 洛谷、牛客网、AcWing 刷题(python版)

    牛客网python专项练习整理(一) https://blog.csdn.net/weixin_41913008/article/details/87203468 牛客网剑指offer--python ...

  8. Linux内核:一文读懂文件系统、缓冲区高速缓存和块设备、超级块

    目录 前言 第一部分 Linux文件系统堆栈 VFS数据结构 文件系统初始化顺序 Dentries 打开文件-说起来容易做起来难! 虚拟文件系统 前言 第二部分 Linux文件系统堆栈 当我们键入&q ...

  9. Pascal版2048

    最近几个月我一直在写2048...前前后后改了好几次,现在大概已经是1.7版本了. 至于2048的规则请自问度娘. 这个版本的2048和原版有了一些不同.. 1.增加分数奖励系统 顾名思义...就是达 ...

  10. 2048Game/2048游戏(自制版)

    2048Game Index of the project/项目主页 Donation/捐助 开发的比较简陋, 因为主要是为了测试. 因此没有GUI, 而且所有函数都编写在cpp里面.很不雅观.请见谅 ...

最新文章

  1. mysql递归sql_SQL如何实现MYSQL的递归查询,SQL实现MYSQL递归
  2. observeOn()与subscribeOn()的详解
  3. 求最小子数组之二维篇
  4. fatal error: alsa/asoundlib.h: 没有那个文件或目录错误解决办法
  5. 语言是用的,把日常的交流转换成其它语言就可以了(转)
  6. 2021年恩阳中学高考成绩查询,巴中市恩阳中学2021年排名
  7. 概念验证_设置成功的UX概念验证
  8. 美国银行将AI应用于企业应收账款处理
  9. 几道题帮你搞定数据选择器
  10. 【算法分析与设计】海盗分硬币问题
  11. Windows内存保护机制及绕过方法
  12. 价值199的wp移植Emlog主题模板PandaPRO
  13. h5正则表达式_正则表达式需要5天才能运行。 因此,我构建了一个可以在15分钟内完成操作的工具。...
  14. c语言生成随机英文字母,菜鸟求助,写一个随机输出26个英文字母的程序
  15. java list find方法_Java 8 Stream - Find Max and Min from List - 入门小站-rumenz.com
  16. Linux操作系统下的多线程编程详细解析----条件变量pthread_cond_t那些事儿
  17. Java集合干货——HashMap源码分析
  18. TDA4VM芯片手册阅读笔记
  19. 最小和最大优先循环队列(C++)
  20. GDI+ 中图片的绘制

热门文章

  1. S7-1500系统内使用ET200S 1SI模块实现Modbus 从站通信
  2. web前端如何提升自我
  3. mysql配置文件在哪_windows下的mysql配置文件在哪
  4. kafka开启kerberos,报错server not found in kerberos database
  5. MDT服务器部署系统,使用MDT2013部署Win8系统之三-配置MDT服务器之导入操作系统...
  6. 【TiChoo资讯站】
  7. Cisco命令大全(清除配置和恢复口令)
  8. 新广告法涉及的敏感词列表
  9. Spring源码下载---导入到Idea
  10. Python线程安全的单例模式