codevs2495 水叮当的舞步
题目描述 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
思路:
IDA*
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<cstdlib> #include<algorithm> using namespace std; const int dx[4]={0,0,1,-1};//扩展联通块时会用上。 const int dy[4]={-1,1,0,0};//扩展联通块时会用上。 int n,ID;//ID用来标记搜索深度。 int map[10][10],cl[10][10];//cl用来存储联通块。 bool used[6];//在估价函数中用来判重。 int get()//获得估价值。 { int ret=0; memset(used,false,sizeof(used)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(!used[map[i][j]] && cl[i][j]!=1) { used[map[i][j]]=true; ret++; } } } return ret; } void dfs(int x,int y,int color)//对联通块进行扩展,color标记当前染的颜色。 { cl[x][y]=1; for(int i=0;i<4;i++) { int nx=x+dx[i],ny=y+dy[i]; if(nx<1 || ny<1 || nx>n || ny>n || cl[nx][ny]==1)continue;//已经在联通块中了。 cl[nx][ny]=2; if(map[nx][ny]==color)dfs(nx,ny,color);//如果发现该点颜色与要染的颜色相同,就以它重新扩展边界。 } } int fill(int color)//该次染色对联通块大小有无影响的判断函数。 { int ret=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(cl[i][j]==2 && map[i][j]==color) { ret++; dfs(i,j,color); } } } return ret; } bool IDAstar(int step)//IDAstar的迭代搜索过程。 { int g=get();//得到估价值。 if(step+g>ID)return false;//超过迭代搜索范围,返回假。 if(!g)return true;//如果找到答案,返回真。 int temp[10][10];//用来暂时保存当前联通块状态。 for(int i=0;i<=5;i++) { memcpy(temp,cl,sizeof(map));//用memcpy函数快捷存储。 if(fill(i) && IDAstar(step+1))return true;//如果此次染色有利于扩大联通块并且染色后能得到答案,就返回真。 memcpy(cl,temp,sizeof(map)); //用memcpy函数快捷存储。 } return false;//以上条件都不满足,返回假。 } main(){ while(cin>>n && n) { memset(cl,0,sizeof(cl)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&map[i][j]); } } dfs(1,1,map[1][1]); for(ID=0;;ID++)//枚举搜索深度限制。 { if(IDAstar(0)) { break;//得到答案后退出循环。 } } cout<<ID<<endl;//输出的为退出时的ID值,即为答案。 } }