IDA*算法,使用连通块之外剩下的颜色个数作为估值函数。每次记录连通块周围颜色,然后改成这个颜色,dfs下去即可。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 9;
typedef pair<int,int>pii;
#define x first
#define y second
int s[N][N],n;
bool st[N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
inline int f(){
int cnt=0;
memset(st,0,sizeof st);
for(register short i=0;i<n;i++)
for(register short j=0;j<n;j++)
if(!st[s[i][j]])st[s[i][j]]=1,cnt++;
return cnt-1;
}
inline void DFS(bool vis[N][N],int x,int y){
vis[x][y]=1;
for(register short i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=n)continue;
if(vis[a][b])continue;
if(s[a][b]!=s[0][0])continue;
DFS(vis,a,b);
}
}
inline void operate(bool vis[N][N],int u){
for(register short i=0;i<n;i++)
for(register short j=0;j<n;j++)
if(vis[i][j])s[i][j]=u;
}
inline bool dfs(int u,int depth,int last){
int res=f();
if(u+res>depth)return false;
if(!res)return true;
bool cor[6],vis[N][N];
memset(vis,0,sizeof vis);
memset(cor,0,sizeof cor);
DFS(vis,0,0);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(vis[i][j])
{
for(register short k=0;k<4;k++)
{
int x=i+dx[k],y=j+dy[k];
if(x<0||x>=n||y<0||y>=n)continue;
if(vis[x][y])continue;
cor[s[x][y]]=1;
}
}
int bk[N][N];
memcpy(bk,s,sizeof s);
for(register short i=0;i<6;i++)
{
if(cor[i]&&i!=last){
operate(vis,i);
if(dfs(u+1,depth,i))return true;
memcpy(s,bk,sizeof bk);
}
}
return false;
}
int main(){
while(scanf("%d",&n),n){
for(register short i=0;i<n;i++)
for(register short j=0;j<n;j++)
scanf("%d",&s[i][j]);
int depth(0);
while(!dfs(0,depth,s[0][0]))depth++;
printf("%d\n",depth);
}
return 0;
}