[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 水叮当得到了一块五颜六色的格子形地毯作为生日礼物 ...
随机推荐
- Asp.Net MVC中捕捉错误路由并设置默认Not Found页面。
在Global中写一个Application_Error捕捉错误路由并重定向到Not Found页面.这里是全局性抓取错误路由,此处还可以写由错误路由导致访问失败的日志记录. protected vo ...
- Android利用Socket与硬件通信之智能家居APP
前几天做一个智能家居APP,硬件段使用的是ESP8266WIFI模块,其实不管是WIFI模块还是蓝牙,通信都是同样一个道理,获取IP和端口来进行通信. 我是通过XCOM v2.0 发送信息,移动端接收 ...
- H3C S5024P交换机 vlan实验
H3C S5024P交换机第二次vlan实验 实验1 与交换机端口G0/1和G0/2相连的PC1与PC2属于VLAN 1,与G0/3和G0/4相连的PC3和PC4属于VLAN 2,PC1.PC2.PC ...
- 《3+1团队》【Alpha】Scrum meeting 3
项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 3+1团队 团队博客地址 https://home.cnblogs.com/u/3-1group ...
- xcode中自定义log打印
打印内容包括 在哪个文件中 ? 在哪个方法中? 将要执行什么操作? // 此打印实现前提: // 1.在.pch文件中实现自定义log打印方法,log名换为LCLog // 2.定义一个宏obje ...
- 122. Best Time to Buy and Sell Stock II@python
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- Python:字体颜色
/033[31;1m /033[0m 字体背景颜色 40:黑 41:深红 42:绿 43:黄色 44:蓝色 45:紫色 46:深绿 47:白色 字体颜色 30:黑 31:红 32:绿 33:黄 ...
- c++_包子凑数
标题:包子凑数 小明几乎每天早晨都会在一家包子铺吃早餐.他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子.每种蒸笼都有非常多笼,可以认为是无限笼. 每当有顾客想买X个包子,卖包子的大叔就会 ...
- JAVA:ssm框架搭建
文章来源:http://www.cnblogs.com/hello-tl/p/8328071.html 环境简介 : jdk1.7.0_25/jdk1.8.0_31 tomcat-7.0.81 m ...
- SolrCloud 概念
原文链接 https://www.w3cschool.cn/solr_doc 当您的集合对于一个节点来说太大时,您可以通过创建多个分片将其分解并分段存储. 碎片是集合的逻辑分区,包含集合中的文档的子集 ...