题目链接:https://cn.vjudge.net/problem/POJ-4007
题解:
将与左上角相连且颜色相同的格子设为A类格子;与A类格子相连的格子,即颜色为A类格子下一步可变为的颜色的格子设为B类格子;将A类格子标记为1,表示当前状态颜色已改变的格子,将B类格子标记为2,表示当前状态颜色可改变的格子。
MHD( )(曼哈顿距离):此题的曼哈顿距离求的是除了A类格子外剩余格子的颜色的数量,也就是最少需要改变颜色的次数。
dfs( )(搜索过程):先判断当前结果是否与假定最优解相同,若不同则判断当前状态的最优解+当前深度是否大于假定最优解(IDA*优化);然后遍历六种颜色,定义一个局部变量记录当前状态(回溯后即可回溯到此状态),找到一个B类格子后改变当前状态(change_state()函数),继续下一步搜索。
change_state( )( 改变状态 ) :将与当前A类格子(进入此调用函数前的刚被标记为A类格子的B类格子,不是其他颜色的A类格子)颜色相同的格子标记为1(标记为A类格子),与其相连的标记为2(标记为B类格子);
总结:
这个题对于自己来说,算是一个经典的题。做的时候不知道该如何回溯,具体搜索的过程思路不太清晰。改变状态时用的也是dfs,自己没有想到。发现自己身上的很大弊端,在做题时没有一个具体明确的思路,很多细节的东西也处理不太好。路还很长,希望自己更加努力吧。
#include<stdio.h>
#include<string.h>
int n;
int c[4][2]= {1,0,0,1,-1,0,0,-1};
int book[10][10];
int Map[10][10];
int min_step;
int flag;
int ans;
int MHD()///曼哈顿距离(求的是当前还剩余的颜色数目);
{
int i,j,k=0,num[10]= {0};
for(i=0; i<n; i++)
for(j=0; j<n; j++)
{
if(book[i][j]==1)
continue;
num[Map[i][j]]=1;
}
for(i=0; i<6; i++)
if(num[i])
k++;
return k;
}
void change_state(int x,int y,int color)///改变当前状态;
{
for(int i=0; i<4; i++)
{
int dx=x+c[i][0];
int dy=y+c[i][1];
if(dx<0||dy<0||dx>=n||dy>=n||book[dx][dy]==1)
continue;
if(Map[dx][dy]==color)
{
book[dx][dy]=1;
change_state(dx,dy,color);
}
else
book[dx][dy]=2;
}
}
void dfs(int s)
{
if(flag)
return ;
int mhd=MHD();
if(s==min_step)
{
if(mhd==0)
{
flag=1;
ans=min_step;
}
return ;
}
if(mhd+s>min_step)///IDA*;
return ;
int i,j,k;
for(i=0; i<6; i++)
{
int last_book[10][10];///定义局部变量储存当前状态;
int cnt=0;
memcpy(last_book,book,sizeof(book));
for(j=0; j<n; j++)
for(k=0; k<n; k++)
{
if(Map[j][k]!=i)
continue;
if(book[j][k]==2)///当前格子为2时表示可改变;
{
book[j][k]=1;
change_state(j,k,i);
cnt++;
}
}
if(!flag&&cnt>0)
dfs(s+1);
if(flag)
return ;
memcpy(book,last_book,sizeof(last_book));///回溯到上一个状态;
}
}
int main()
{
while(~scanf("%d",&n)&&n)
{
int i,j;
for(i=0; i<n; i++)
for(j=0; j<n; j++)
scanf("%d",&Map[i][j]);
memset(book,0,sizeof(book));
book[0][0]=1;//左上角的格子为A类格子;
change_state(0,0,Map[0][0]);
min_step=MHD();///假定最优解;
flag=0;
while(!flag)
{
dfs(0);
min_step++;
}
printf("%d\n",ans);
}
}