[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]水叮当的舞步的更多相关文章

  1. codevs2495 水叮当的舞步 IDA*

    我打暴力不对,于是就看看题解,,,,,,IDA*就是限制搜索深度而已,这句话给那些会A*但不知道IDA*是什么玩意的小朋友 看题解请点击这里 上方题解没看懂的看看这:把左上角的一团相同颜色的范围,那个 ...

  2. codevs 2495 水叮当的舞步

    题目链接:水叮当的舞步 我现在开始发题目链接了(主要还是因为懒得整理题面)-- 这道题一开始是看到MashiroSky在写,于是我也开始写这道题了(说白了就是狙击他)-- 这道题看到这么小的范围当然给 ...

  3. 【IDA*】codevs 2495:水叮当的舞步

    2495 水叮当的舞步 题目描述 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变. 为了讨好她的偶像虹猫,水叮当决定在地毯上 ...

  4. bzoj 3041: 水叮当的舞步 迭代加深搜索 && NOIP RP++

    3041: 水叮当的舞步 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 72  Solved: 44[Submit][Status] Descript ...

  5. 【BZOJ3041】水叮当的舞步 迭代深搜IDA*

    [BZOJ3041]水叮当的舞步 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变.为了讨好她的偶像虹猫,水叮当决定在地毯上跳 ...

  6. bzoj3041 水叮当的舞步 IDA*

    水叮当的舞步 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 230  Solved: 107[Submit][Status][Discuss] Des ...

  7. BZOJ 3041 水叮当的舞步

    3041: 水叮当的舞步 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 120  Solved: 67[Submit][Status][Discuss ...

  8. 【codevs2495】水叮当的舞步

    题目描述 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变.为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~ ...

  9. Bzoj3041 水叮当的舞步

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 132  Solved: 75 Description 水叮当得到了一块五颜六色的格子形地毯作为生日礼物 ...

随机推荐

  1. C#基础学习5

    数组集合

  2. jmeter压测--从文本中读取参数

    由于之前从数据库获取查询结果作为请求的入参(使用场景:测试一个接口并发处理数据的能力,并且每次请求传入的参数都要不同.),会一定程度上造成对数据库的压测,在没有完全搞清楚多线程之间参数的传递之前,我们 ...

  3. 动手实现 Redux(二):抽离 store 和监控数据变化

    上一节 的我们有了 appState 和 dispatch: let appState = { title: { text: 'React.js 小书', color: 'red', }, conte ...

  4. 你干啥的?Lombok

    01.Lombok 的自我介绍 Lombok 在官网是这样作自我介绍的: Project Lombok makes java a spicier language by adding 'handler ...

  5. 在WIN7下解决coursera视频无法播放问题

    https://blog.csdn.net/u012509485/article/details/78459584在WIN7下解决coursera视频无法播放问题2019/1/20 23:18 最近C ...

  6. android动画之通过子线程来实现动画

    android动画之通过子线程来实现动画 使用android动画机制,往往是相对于原始位置来进行参照. 这里通过子线程修改物体位置实现动画. 布局文件: <RelativeLayout xmln ...

  7. Git使用简析

    推送本地操作 初始化一个本地Git仓库,在需要添加版本控制的文件夹根目录中使用git init命令. 添加文件到本地Git仓库: git add 文件名 # 添加文件到暂存区 git add . # ...

  8. HYSBZ 1086 王室联邦 (树的分块)

    题意:国王想把他的国家划分成若干个省.他的国家有n个城市,是一棵树,即n-1条边,编号为1..n.为了防止管理太过分散,每个省至少要有B个城市,为了能有效的管理,每个省最多只有3B个城市.每个省必须有 ...

  9. (转)在编写Spring框架的配置文件时,标签无提示符的解决办法

    http://blog.csdn.net/yerenyuan_pku/article/details/52831618 问题描述 初学者在学习Spring框架的过程中,大概会碰到这样一个问题:在编写S ...

  10. gym 100947I (求因子)

    What a Mess Alex is a very clever boy, after all he is the son of the greatest watchmaker in Odin. O ...