[codevs2495]水叮当的舞步
[codevs2495]水叮当的舞步
试题描述
水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变。
为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~
地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。
输入
每个测试点包含多组数据。
每组数据的第一行是一个整数N,表示地摊上的格子有N行N列。
接下来一个N*N的矩阵,矩阵中的每个数都在0~5之间,描述了每个格子的颜色。
N=0代表输入的结束。
输出
对于每组数据,输出一个整数,表示最少步数。
输入示例
输出示例
数据规模及约定
对于30%的数据,N<=5
对于50%的数据,N<=6
对于70%的数据,N<=7
对于100%的数据,N<=8,每个测试点不多于20组数据。
题解
依然是迭代加深搜索。
但是需要几个优化。
我先贴一份 T 的代码上来:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 10
int n, A[maxn][maxn]; struct Point {
int x, y;
Point() {}
Point(int _, int __): x(_), y(__) {}
} Q[maxn*maxn];
int hd, tl, dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
bool vis[maxn][maxn], get[maxn];
bool isin(int x, int y) { return 1 <= x && x <= n && 1 <= y && y <= n; }
void bfs() {
memset(vis, 0, sizeof(vis)); vis[1][1] = 1;
hd = tl = 0; Q[++tl] = Point(1, 1);
memset(get, 0, sizeof(get));
while(hd < tl) {
Point u = Q[++hd];
for(int i = 0; i < 4; i++) {
Point v(u.x + dx[i], u.y + dy[i]);
if(isin(v.x, v.y) && !vis[v.x][v.y]) {
if(A[v.x][v.y] != A[1][1]) get[A[v.x][v.y]] = 1;
else vis[v.x][v.y] = 1, Q[++tl] = v;
}
}
}
return ;
}
void print() {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) printf("%d%c", A[i][j], j < n ? ' ' : '\n');
putchar('\n');
return ;
}
bool dfs(int cur, int K) {
bool ok = 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) if(A[i][j] != A[1][1]) {
ok = 0; break;
}
if(!ok) break;
}
// printf("%d(%d):\n", cur, K); print();
if(ok) return printf("%d\n", K), 1;
if(cur == K) return 0;
// printf("%d(%d):\n", cur, K); print();
int B[maxn][maxn];
bool Vis[maxn][maxn], Get[maxn];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) B[i][j] = A[i][j];
bfs();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) Vis[i][j] = vis[i][j];
for(int i = 0; i <= 5; i++) Get[i] = get[i];
for(int i = 0; i <= 5; i++) if(Get[i]) {
for(int x = 1; x <= n; x++)
for(int y = 1; y <= n; y++) if(Vis[x][y])
A[x][y] = i;
// printf("%d(%d) turn to:\n", cur, K); print();
if(dfs(cur + 1, K)) return 1;
for(int x = 1; x <= n; x++)
for(int y = 1; y <= n; y++) A[x][y] = B[x][y];
}
return 0;
} int main() {
while(1) {
n = read(); if(!n) break;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) A[i][j] = read(); for(int i = 0; !dfs(0, i); i++) ;
} return 0;
}
这份代码中 dfs 每深入一层,就必定进行一遍 bfs,是非常耗时间的。
所以我们考虑不用 bfs,模了一下黄学长的题解后,明白了可以通过打标记的方式维护当前状态,即:已经同色的区域用 1 做标记,同色区域周围用 2 做标记,然后每次向外扩展时显然只用考虑标 2 的部分,我们动态地更新这些标记,就不用每次都 bfs 了。
但这样还不够,我们需要加剪枝:最好的情况莫过于每次减少当前地图中的一种颜色,如果“当前地图没标 1 的部分的颜色种类数 + 当前步数 > 迭代加深搜索限制的步数”的话,就可以跳出了。
此外,向外扩张时,已经考虑过的颜色不必重复考虑了,这也是一个重要的优化。
最终 AC 代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 10
int n, A[maxn][maxn], vis[maxn][maxn], dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0}; void print() {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) printf("%d%c", vis[i][j], j < n ? ' ' : '\n');
putchar('\n');
return ;
}
bool isin(int x, int y) { return 1 <= x && x <= n && 1 <= y && y <= n; } void dfs(int x, int y, int col) {
vis[x][y] = 1;
for(int i = 0; i < 4; i++) {
int vx = x + dx[i], vy = y + dy[i];
if(isin(vx, vy) && !vis[vx][vy]) {
vis[vx][vy] = 2;
if(A[vx][vy] == col) dfs(vx, vy, col);
}
}
return ;
}
void mark(int col) {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(vis[i][j] == 2 && A[i][j] == col) dfs(i, j, col);
return ;
}
int cal() {
bool has[6]; memset(has, 0, sizeof(has));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(vis[i][j] != 1) has[A[i][j]] = 1;
int cnt = 0;
for(int i = 0; i < 6; i++) cnt += has[i];
return cnt;
}
bool solve(int cur, int K) {
// printf("%d(%d):\n", cur, K); print();
int cnt = cal();
if(!cnt) return printf("%d\n", K), 1;
if(cur == K || cnt + cur > K) return 0;
int B[maxn][maxn];
bool has[6]; memset(has, 0, sizeof(has));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) if(vis[i][j] == 2 && !has[A[i][j]]) {
memcpy(B, vis, sizeof(vis));
mark(A[i][j]); has[A[i][j]] = 1;
if(solve(cur + 1, K)) return 1;
memcpy(vis, B, sizeof(vis));
}
return 0;
} int main() {
while(1) {
n = read(); if(!n) break;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) A[i][j] = read(); memset(vis, 0, sizeof(vis));
vis[1][1] = 2; mark(A[1][1]);
for(int i = 0; !solve(0, i); i++) ;
} return 0;
}
[codevs2495]水叮当的舞步的更多相关文章
- codevs2495 水叮当的舞步 IDA*
我打暴力不对,于是就看看题解,,,,,,IDA*就是限制搜索深度而已,这句话给那些会A*但不知道IDA*是什么玩意的小朋友 看题解请点击这里 上方题解没看懂的看看这:把左上角的一团相同颜色的范围,那个 ...
- codevs 2495 水叮当的舞步
题目链接:水叮当的舞步 我现在开始发题目链接了(主要还是因为懒得整理题面)-- 这道题一开始是看到MashiroSky在写,于是我也开始写这道题了(说白了就是狙击他)-- 这道题看到这么小的范围当然给 ...
- 【IDA*】codevs 2495:水叮当的舞步
2495 水叮当的舞步 题目描述 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变. 为了讨好她的偶像虹猫,水叮当决定在地毯上 ...
- bzoj 3041: 水叮当的舞步 迭代加深搜索 && NOIP RP++
3041: 水叮当的舞步 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 72 Solved: 44[Submit][Status] Descript ...
- 【BZOJ3041】水叮当的舞步 迭代深搜IDA*
[BZOJ3041]水叮当的舞步 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变.为了讨好她的偶像虹猫,水叮当决定在地毯上跳 ...
- bzoj3041 水叮当的舞步 IDA*
水叮当的舞步 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 230 Solved: 107[Submit][Status][Discuss] Des ...
- BZOJ 3041 水叮当的舞步
3041: 水叮当的舞步 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 120 Solved: 67[Submit][Status][Discuss ...
- 【codevs2495】水叮当的舞步
题目描述 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变.为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~ ...
- Bzoj3041 水叮当的舞步
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 132 Solved: 75 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物 ...
随机推荐
- [已读]编写高质量代码 改善JavaScript程序的188个建议
吐槽一万遍,买的最后悔的一本,没有之一,大量篇幅抄袭<高性能javascript>,我记得还有部分抄袭<javascript精粹>,<javascript模式>有没 ...
- 下载JSTL方法
第一步:访问 http://www.apache.org/dist/ 第二步:点击jakarta
- Phalcon初认识
Phalcon以c扩展交付的全堆栈php开发框架 基本功能 低开销:低内存消耗和CPU相比传统的框架 MVC和HMVC:模块.组件.模型.视图和控制器 依赖注入:依赖注入和位置的服务和它的本身他们的容 ...
- SQL Server2012 T-SQL对分页的增强尝试
简介 SQL Server 2012中在Order By子句之后新增了OFFSET和FETCH子句来限制输出的行数从而达到了分页效果.相比较SQL Server 2005/2008的ROW_Numbe ...
- windows 下防火墙安全加固,配置规则
netsh advfirewall firewall: 显示关于防火墙操作的常见命令的帮助信息 netsh advfirewall firewall show rule name=all dir=in ...
- mac homebrew安装
http://book.51cto.com/art/201107/278761.htm 3.2.3 使用 Homebrew 安装 Git Mac OS X 有好几个包管理器,用于管理一些开源软件在 M ...
- 植物大战僵尸游戏的开发(python)
装备东西: 搭建好python环境, 四张图片,(背景图片,炮弹图片,僵尸图片,豌豆图片),就ok了 没有安装pygame的需要进行安装 pip install pygame 参考视频 # 植物大 ...
- qs库 是将url参数和json互转 | query strings 缩写 | import qs from 'qs'
import qs from 'qs' 1.npm地址 https://www.npmjs.com/package/qs 2.概述 将url中的参数转为对象: 将对象转为url参数形式 3.示例 ...
- CPP-基础:inline
背景: 在C&C++中 一.inline关键字用来定义一个类的内联函数,引入它的主要原因是用它替代C中表达式形式的宏定义. 表达式形式的宏定义一例: #define ExpressionNam ...
- PHP06 流程控制
学习要点 选择结构 循环结构 学习目标 掌握PHP的选择结构 掌握PHP的循环结构 流程控制概述 程序 程序:一系列计算机指令的集合. 编程语言:开发程序的工具. 程序执行结构 计算机程序有三种基本执 ...