[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 水叮当得到了一块五颜六色的格子形地毯作为生日礼物 ...
随机推荐
- 136 Single Number 数组中除一个数外其他数都出现两次,找出只出现一次的数
给定一个整数数组,除了某个元素外其余元素均出现两次.请找出这个只出现一次的元素.备注:你的算法应该是一个线性时间复杂度. 你可以不用额外空间来实现它吗? 详见:https://leetcode.com ...
- rhel7使用centos7yum组件
1)rpm -qa|grep yum --查看已安装的yum组件包 2)rpm -e 包名 --nodeps --卸载包 3)下载安装以下组件包: 使用rpm -ivh yum-* yum-3.4.3 ...
- 在linux中使用多个redis端口来构建redis集群
大家好,这是我制作的redis集群搭建视频教程. 服务器:ubnutu server(版本18.10) redis:redis-4.0.12 我这里就简单说明下大概步骤了,详细请观看教学视频. 首先更 ...
- Java GUI简介
Java有2个GUI库:AWT.Swing. AWT是SUN最早提供的GUI库,依赖本地平台,界面不好看,功能有限.之后推出了Swing,Swing并没有完全替代AWT,而是建立在AWT基础上的.Sw ...
- leetcode410 Split Array Largest Sum
思路: dp. 实现: class Solution { public: int splitArray(vector<int>& nums, int m) { int n = nu ...
- 关于setTimeout和Promise执行顺序问题
先看一段代码 console.log('打印'+1); setTimeout(function(){ console.log('打印'+2); }) new Promise(function(reso ...
- pandas中loc-iloc-ix的使用
转自:https://www.jianshu.com/p/d6a9845a0a34 Pandas中loc,iloc,ix的使用 使用 iloc 从DataFrame中筛选数据 iloc 是基于“位置” ...
- ubuntu下安装apcu扩展
apcu前身是apc,apc分为系统缓存和用户缓存 1.系统缓存是指PHP执行时增加缓存,减少PHP文件的反复检查和编译,从而达到系统加速的目的. 2.用户缓存是指,PHP代码中将数据写入缓存,是用户 ...
- https为数据传输保驾护航
为什么要使用https 谷歌官网已宣布,今年7月起,Chrome浏览器的地址栏将把所有HTTP标示为不安全网站. 在客户端与服务器数据传输过程中,http协议传输是不安全的,一般情况下,http协议的 ...
- LibreOJ #119. 最短路 (堆优化dijkstra)
题目描述 给一个 n(1≤2500≤n) n(1 \leq 2500 \leq n)n(1≤2500≤n) 个点 m(1≤6200≤m) m(1 \leq 6200 \leq m)m(1≤6200≤m ...