题目描述 Description
水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变。
为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~
地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。
输入描述 Input Description
每个测试点包含多组数据。
每组数据的第一行是一个整数N,表示地摊上的格子有N行N列。
接下来一个N*N的矩阵,矩阵中的每个数都在0~5之间,描述了每个格子的颜色。
N=0代表输入的结束。
样例输入 Sample Input
2
0 0
0 0
3
0 1 2
1 1 2
2 2 1
0
数据范围及提示 Data Size & Hint
对于30%的数据,N<=5
对于50%的数据,N<=6
对于70%的数据,N<=7
对于100%的数据,N<=8,每个测试点不多于20组数据。
第二组样例解释:
0 1 2 1 1 2 2 2 2 1 1 1
1 1 2 --> 1 1 2 --> 2 2 2 --> 1 1 1
2 2 1 2 2 1 2 2 1 1 1 1
来源:Nescafe 21
感触:(不敢说是思路)
网上说此题最后一个点卡常数,
,dfs肯定跑不快,这不明显坑爹吗!~
网上有大神和我写的差不多的,各种优化,最关键人家是用bfs搜过的。
dfs改bfs,bfs不知道哪写错了。
所有答案都WA了。(bfs部分引去了)
挑了1个多小时,实在调不出来了。放弃了。。。
~~~~(>_<)~~~~ 又舍不得扔。
90分代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline const int read(){
register int x=0,f=1;
register char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
return ch-'0';
}
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
const int N=9;
int n,g[N][N],a[N][N];
bool flag,vis[N][N],mark[N];
inline void calc(int &c){
memset(mark,0,sizeof mark);
c=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(!mark[a[i][j]]){
mark[a[i][j]]=1;
c++;
}
}
}
}
void go(int x,int y,int c,int r){
a[x][y]=r;
vis[x][y]=1;
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(!vis[nx][ny]&&nx>0&&nx<=n&&ny>0&&ny<=n&&a[nx][ny]==c){
go(nx,ny,c,r);
}
}
}
void get_round(int x,int y,int c,int round[]){
vis[x][y]=1;
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(!vis[nx][ny]&&nx>0&&nx<=n&&ny>0&&ny<=n){
if(a[nx][ny]==c) get_round(nx,ny,c,round);
else if(!round[a[nx][ny]]) round[a[nx][ny]]=1;
}
}
}
/*
#define xx first
#define yy second
pair<int,int>q[800000];
void go(int x,int y,int c,int r){
a[x][y]=r;
vis[x][y]=1;
int h=0,t=1;
while(h!=t){
++h;
for(int i=0;i<4;i++){
int nx=q[h].xx;
int ny=q[h].yy;
if(!vis[nx][ny]&&nx>0&&nx<=n&&ny>0&&ny<=n&&a[nx][ny]==c){
vis[nx][ny]=1;
a[nx][ny]=r;
++t;
q[t]=make_pair(nx,ny);
}
}
}
}
void get_round(int x,int y,int c,int round[]){
vis[x][y]=1;
int h=0,t=1;
while(h!=t){
++h;
for(int i=0;i<4;i++){
int nx=q[h].xx;
int ny=q[h].yy;
if(!vis[nx][ny]&&nx>0&&nx<=n&&ny>0&&ny<=n){
if(a[nx][ny]==c){
vis[nx][ny]=1;
++t;
q[t]=make_pair(nx,ny);
}
else if(!round[a[nx][ny]]) round[a[nx][ny]]=1;
}
}
}
}*/
void dfs(int now,int sum){
if(flag) return ;
int C;
calc(C);
if(now==sum){
if(C==1) flag=1;
return ;
}
if(now+C-1>sum) return ;
memset(vis,0,sizeof vis);
int round[N]={0};
get_round(1,1,a[1][1],round);
for(int i=0;i<=5;i++){
if(i==a[1][1]||!round[i]) continue;
int back[N][N];
memcpy(back,a,sizeof a);
memset(vis,0,sizeof vis);
go(1,1,a[1][1],i);
if(flag) return ;
dfs(now+1,sum);
memcpy(a,back,sizeof back);
}
}
int main(){
freopen("sh.txt","r",stdin);
for(;;){
n=read();
if(!n) break;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i][j]=read();
}
}
int ans=0;
for(int k=0;k<=16;k++){
memcpy(a,g,sizeof g);
flag=0;
dfs(0,k);
if(flag){
ans=k;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
AC的艰辛:

题解:
主要是优化了我的“大水漫灌”函数:(基本上都改了)
我们可以发现,每次寻找左上角的格子所在的联通块耗费的时间常数巨大。因此我们在这里寻求突破。
我们引入一个N*N的v数组。左上角的格子所在的联通块里的格子标记为1。左上角联通块周围一圈格子标记为2,其它格子标记为0。如果某次选择了颜色c,我们只需要找出标记为2并且颜色为c的格子,向四周扩展,并相应地修改v标记,就可以不断扩大标记为1的区域,最终如果所有格子标记都是1,那么显然找到了答案。(参考黄学长的博客)
AC代码:
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术