【BZOJ3041】水叮当的舞步

Description

水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变。
为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~
地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。

Input

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

Output

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

Sample Input

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

Sample Output

0
3
对于100%的数据,N<=8,每个测试点不多于20组数据。

题解:迭代搜索,即每次设定一个深度,DFS到这个深度时便停止搜索。如果当前深度下找不到解,则深度++。

但是本题直接迭代搜索会TLE,我们需要加剪枝。我(chao)的剪枝方法如下:

1.如果我们选择将左上角的联通块颜色变为x,但是染色后联通块的大小并没有增大,则不进行这次染色。
2.我们设定一个估价函数g=剩余的颜色数-1,那么当g>剩余的迭代次数时,则停止搜索。

然后就光荣的11s卡过,变成status倒数第一~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
int n,flag;
bool vis[8][8],used[8];
struct node
{
int v[8][8],lft,cnt;
int * operator [] (int a) {return v[a];}
node () {memset(v,0,sizeof(v)),lft=0;}
};
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
void color(node &a,int x,int y,int val)
{
if(!x&&!y) memset(vis,0,sizeof(vis));
vis[x][y]=1;
for(int i=0;i<4;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(tx<0||tx>=n||ty<0||ty>=n||a[tx][ty]!=a[x][y]||vis[tx][ty]) continue;
color(a,tx,ty,val);
}
a[x][y]=val;
}
void count(node &a,int x,int y)
{
if(!x&&!y) a.cnt=0,memset(vis,0,sizeof(vis));
a.cnt++,vis[x][y]=1;
for(int i=0;i<4;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(tx<0||tx>=n||ty<0||ty>=n||a[tx][ty]!=a[x][y]||vis[tx][ty]) continue;
count(a,tx,ty);
}
}
void getlft(node &a)
{
memset(used,0,sizeof(used));
a.lft=-1;
for(int i=0;i<n;i++) for(int j=0;j<n;j++) a.lft+=(!used[a[i][j]]),used[a[i][j]]=1;
}
void dfs(node a,int x)
{
if(a.lft>x) return ;
if(!x)
{
flag=1;
return ;
}
for(int i=0;i<=5&&!flag;i++)
{
if(i==a[0][0]) continue;
node b=a;
color(b,0,0,i),count(b,0,0);
if(b.cnt>a.cnt) getlft(b),dfs(b,x-1);
}
}
void work()
{
int i,j;
node a;
for(i=0;i<n;i++) for(j=0;j<n;j++) scanf("%d",&a[i][j]);
getlft(a),count(a,0,0);
for(flag=0,i=a.lft;i<=60;i++)
{
dfs(a,i);
if(flag)
{
printf("%d\n",i);
return ;
}
}
}
int main()
{
while(1)
{
scanf("%d",&n);
if(!n) return 0;
work();
}
}
05-11 11:03