隐藏页面特效

Codevs 2495 水叮当的舞步

2495 水叮当的舞步

 

 时间限制: 1 s
 空间限制: 32000 KB
 题目等级 : 钻石 Diamond
 
 
题目描述 Description

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

  地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
  水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
  由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。

输入描述 Input Description

  每个测试点包含多组数据。
  每组数据的第一行是一个整数N,表示地摊上的格子有N行N列。
  接下来一个N*N的矩阵,矩阵中的每个数都在0~5之间,描述了每个格子的颜色。
  N=0代表输入的结束。

输出描述 Output Description

  对于每组数据,输出一个整数,表示最少步数。

样例输入 Sample Input

2
0 0 
0 0
3
0 1 2
1 1 2
2 2 1
0

样例输出 Sample Output

0
3

数据范围及提示 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代码:

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int dx[]={0,0,1,-1}; const int dy[]={1,-1,0,0}; const int N=9; int n,mp[N][N]; int mark[N][N]; bool ans,vis[N]; int s; inline int get(){ int t=0; memset(vis,0,sizeof vis); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(!vis[mp[i][j]]&&mark[i][j]!=1){ vis[mp[i][j]]=1; t++; } } } return t; } void dfs(int x,int y,int val){ mark[x][y]=1; for(int i=0;i<4;i++){ int nx=x+dx[i]; int ny=y+dy[i]; if(nx<1||nx>n||ny<1||ny>n||mark[nx][ny]==1) continue; mark[nx][ny]=2; if(mp[nx][ny]==val) dfs(nx,ny,val); } } inline int fill(int x){ int t=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(mark[i][j]==2&&mp[i][j]==x){ t++; dfs(i,j,x); } } } return t; } void search(int k){ int v=get(); if(!v) ans=1; if(k+v>s||ans) return ; int tmp[N][N]; for(int i=0;i<=5;i++){ memcpy(tmp,mark,sizeof mark); if(fill(i)) search(k+1); memcpy(mark,tmp,sizeof mark); } } int main(){ freopen("sh.txt","r",stdin); for(scanf("%d",&n);n;scanf("%d",&n)){ memset(mark,0,sizeof mark); ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&mp[i][j]); } } dfs(1,1,mp[1][1]); for(s=0;;s++){ search(0); if(ans){printf("%d\n",s);break;} } } return 0; }

 


__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/5823486.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(309)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示