【Luogu】P1312Mayan游戏(暴搜)
由于是暴搜题,所以这篇博客只讲怎么优化剪枝,以及一些细节。
模拟消除思路:因为消除可以拆分成小的横条或竖条,而这些条的长度至少为三,所以一块可消除的区域至少会有一个中心点。这里的中心点可以不在正中间,只需要不是条上的第一个或者最后一个。
于是枚举中间点,搜索它为中心最多向四个方向能扩展多远。如果搜索出来的横向满足长度要求,或竖向满足长度要求,就给他们打上一个标记。
注意,这里只是打上标记,不能直接清零,很可能另一个方块的结算还得用到这个方块。
等到枚举所有的中间点并给所有可消除的方块打上标记之后,可以把所有标记上的方块清空。然后检查有没有地方可以落下去。
注意所有方块落下去之后还有可能接着消消乐,所以在落完之后还要再循环回去检查有没有可消除的方块。这里使用一个递归的代码来实现。
int count(int x){
bool vis[][],flag=;
int cnt=;
memset(vis,,sizeof(vis));
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j){
int col=Map[x][i][j];
if(!col) continue;
int u=i,d=i,l=j,r=j;
while(u>&&Map[x][u-][j]==col) u--;
while(d<n&&Map[x][d+][j]==col) d++;
while(l>&&Map[x][i][l-]==col) l--;
while(r<m&&Map[x][i][r+]==col) r++;
if(d-u>=)
for(int k=u;k<=d;++k) vis[k][j]=;
if(r-l>=)
for(int k=l;k<=r;++k) vis[i][k]=;
}
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j)
if(vis[i][j]){
Map[x][i][j]=; cnt++;
}
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j)
if(!Map[x][i][j]){
int s=i;
while(s<n&&!Map[x][s][j]) s++;
if(!Map[x][s][j]) continue;
flag=;
Map[x][i][j]=Map[x][s][j];
Map[x][s][j]=;
}
if(flag) cnt+=count(x);
return cnt;
}
注意最后倒数第三行。flag表示的是有没有方块落下,因为有落下方块就有新一轮消除的可能性,所以可以递归这个函数,直到没有任何方块落下为止。此时递归终止,开始回溯计算答案。
再说说剪枝的几个小技巧。
1、优先考虑坐标字典序小的向右移动,这样一旦搜到答案就是字典序最小的解。
2、只有当左边没有方块的时候才向左移动,否则右面方块向左移动等价于左面方块向右移动,而这个状态已经搜过了。
3、不交换两个颜色相同的方块。这个没什么好说的。
最后给出代码。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std; inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} int num;
int n=,m=;
int Max;
int Map[][][];
int posx[],posy[],move[]; inline void copy(int x){
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j) Map[x+][i][j]=Map[x][i][j];
} int count(int x){
bool vis[][],flag=;
int cnt=;
memset(vis,,sizeof(vis));
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j){
int col=Map[x][i][j];
if(!col) continue;
int u=i,d=i,l=j,r=j;
while(u>&&Map[x][u-][j]==col) u--;
while(d<n&&Map[x][d+][j]==col) d++;
while(l>&&Map[x][i][l-]==col) l--;
while(r<m&&Map[x][i][r+]==col) r++;
if(d-u>=)
for(int k=u;k<=d;++k) vis[k][j]=;
if(r-l>=)
for(int k=l;k<=r;++k) vis[i][k]=;
}
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j)
if(vis[i][j]){
Map[x][i][j]=; cnt++;
}
for(register int i=;i<=n;++i)
for(register int j=;j<=m;++j)
if(!Map[x][i][j]){
int s=i;
while(s<n&&!Map[x][s][j]) s++;
if(!Map[x][s][j]) continue;
flag=;
Map[x][i][j]=Map[x][s][j];
Map[x][s][j]=;
}
if(flag) cnt+=count(x);
return cnt;
} void dfs(int use,int deep){
if(use!=&&deep==Max) return;
if(use==){
if(deep==Max){
for(int i=;i<=Max;++i) printf("%d %d %d\n",posy[i]-,posx[i]-,move[i]);
exit();
}
return;
}
copy(deep);
for(register int j=;j<=m;++j)
for(register int i=;i<=n;++i){
if(!Map[deep][i][j]) continue;
if(Map[deep][i][j]!=Map[deep][i][j+]&&j<m){
int a=Map[deep][i][j],b=Map[deep][i][j+];
Map[deep+][i][j]=b;Map[deep+][i][j+]=a;
posx[deep+]=i; posy[deep+]=j; move[deep+]=;
int q=count(deep+);
dfs(use-q,deep+);
copy(deep);
}
if(!Map[deep][i][j-]&&j>){
int a=Map[deep][i][j],b=Map[deep][i][j-];
Map[deep+][i][j]=b;Map[deep+][i][j-]=a;
posx[deep+]=i; posy[deep+]=j; move[deep+]=-;
int s=i;
while(s>&&Map[deep+][s-][j-]==){
Map[deep+][s--][j-]=;
Map[deep+][s][j-]=a;
}
int q=count(deep+);
dfs(use-q,deep+);
copy(deep);
}
}
} int main(){
Max=read();
int start=;
for(int i=;i<=m;++i)
for(int j=;;j++){
Map[][j][i]=read();
if(Map[][j][i]==) break;
start++;
}
dfs(start,);
printf("-1");
return ;
}
【Luogu】P1312Mayan游戏(暴搜)的更多相关文章
- 洛谷 1312 Mayan游戏——暴搜+剪枝
题目:https://www.luogu.org/problemnew/show/P1312 自己写了很久.又T又WA的. 发现对题理解有误.改完后应该只有T了,但还是T的. 自己写了许多剪枝,很鸡肋 ...
- NOIP 2011 Mayan游戏 大暴搜
题目链接:https://www.luogu.org/problemnew/show/P1312 我的第一篇题解!! 当然感谢ZAGER 的提示,他的链接https://www.cnblogs.com ...
- 【BZOJ-3033】太鼓达人 欧拉图 + 暴搜
3033: 太鼓达人 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 204 Solved: 154[Submit][Status][Discuss] ...
- c++20701除法(刘汝佳1、2册第七章,暴搜解决)
20701除法 难度级别: B: 编程语言:不限:运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 输入正整数n,按从小到大的顺序输出所有 ...
- Codeforces Round #238 (Div. 2) D. Toy Sum 暴搜
题目链接: 题目 D. Toy Sum time limit per test:1 second memory limit per test:256 megabytes 问题描述 Little Chr ...
- poj 3080 Blue Jeans(水题 暴搜)
题目:http://poj.org/problem?id=3080 水题,暴搜 #include <iostream> #include<cstdio> #include< ...
- Sicily1317-Sudoku-位运算暴搜
最终代码地址:https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1317.c 这题博主刷了1天,不是为了做出来,AC ...
- codeforces 339C Xenia and Weights(dp或暴搜)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Xenia and Weights Xenia has a set of weig ...
- Usaco 2.3 Zero Sums(回溯DFS)--暴搜
Zero SumConsider the sequence of digits from 1 through N (where N=9) in increasing order: 1 2 3 ... ...
随机推荐
- Spring MVC系列[2]——参数传递及重定向
1.目录结构 2.代码 <?xml version="1.0" encoding="UTF-8"?> <web-app version=&qu ...
- 【Web应用-大文件部署】上传超过 2M 的文件到 Azure PHP 网站失败
问题描述 上传超过 2M 的文件到 Azure PHP 网站失败. 问题分析 由于 PHP 本身默认上传文件的上限是 2M,所以当上传超过2M的文件时会报错. 解决方法 根据以下步骤进行配置: 在 s ...
- 电脑连接海信电视 HDMI
注意:我们家的电视是海信的,所以不能代表所有的电视哦~~~ 家里电视有线电视已经过期很长时间了,早就想把电脑连接到电视上用电视做显示器的心了,今天来兴趣了,就弄了一下!!! 用电脑连接电视需要先解决两 ...
- Stream.iterate方法与UnaryOperator
前提:本人在翻看<Java核心技术II>的时候在p17的时候发现一段代码不是很明白.不知道为什么就输出了1,2,3,4,5,6,7,8,9,10,...也不知道n-n.add(BigInt ...
- Vue+webpack+echarts+jQuery=demo
需要的插件: "dependencies": { "bootstrap": "^3.3.7", "echarts": & ...
- caffe的调试技巧 和 使用split层
1.网络中的layer层的输出,只要没有作为其他层的输入,caffe的日志就会把这个top输出(如果你用那个网站画网络结构图,你也会发现这种情况的层的颜色是不一样的,是紫色的) 2.如果你想看某一层在 ...
- Hopfield 网络(下)
讲的什么 这部分主要讲离散的 Hopfield 网络权值的计算方法,以及网络记忆容量.主要参考了网上搜到的一些相关 PPT. DHNN 的训练方法 常见的学习方法中有海布法,还有 \(\delta ...
- leetcode_day1
1.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样 ...
- 修改visual studio setup 安装顺序(解决新版安装包无法自动移除老版本程序的问题)
背景 visual studio setup 支持自动删除之前版本的安装,需要设置RemovePreviousVersions = true, DetectNewerInstalledVersion ...
- 《3+1团队》第八次团队作业:Alpha冲刺
项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 3+1团队 团队博客地址 https://home.cnblogs.com/u/3-1group ...