hdu Flood-it!(IDA*算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4127

Flood-it!

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1703    Accepted Submission(s): 396


Problem Description
Flood-it is a fascinating puzzle game on Google+ platform. The game interface is like follows:

At the beginning of the game, system will randomly generate an N×N square board and each grid of the board is painted by one of the six colors. The player starts from the top left corner. At each step, he/she selects a color and changes all the grids connected with the top left corner to that specific color. The statement “two grids are connected” means that there is a path between the certain two grids under condition that each pair of adjacent grids on this path is in the same color and shares an edge. In this way the player can flood areas of the board from the starting grid (top left corner) until all of the grids are in same color. The following figure shows the earliest steps of a 4×4 game (colors are labeled in 0 to 5):

Given a colored board at very beginning, please find the minimal number of steps to win the game (to change all the grids into a same color).

 

Input
The input contains no more than 20 test cases. For each test case, the first line contains a single integer N (2<=N<=8) indicating the size of game board.

The following N lines show an N×N matrix (a i,j) n×n representing the game board. a i,j is in the range of 0 to 5 representing the color of the corresponding grid.
The input ends with N = 0.
 

Output
For each test case, output a single integer representing the minimal number of steps to win the game.
 

Sample Input
  
  
2 0 0 0 0 3 0 1 2 1 1 2 2 2 1 0
 

Sample Output
  
  
0 3
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   4123  4122  4124  4125  4126 

题目大意:n*n的方格,每次从左上角染色,只能染色相连相同的数字,变化过之后就合成一块,下次要变这一块一起变成其他任意的颜色。最终要输出最少多少步能够变成同一个数字。
特别注意:
1、每次变只能变左上角的数字。或者已经与左上角合成一块了就可以一起改变。
2、状态数比较多,用bfs很显然会爆掉,,第一次做IDA*搜索题目。首先,和左上角在一个连通块的将vis标记为1,其次,和连通块的颜色不同,但是相邻的,标记为2,下次可以可改变的颜色。
3、估价函数,用来计算最理想状态下的最优值。

详见代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

int dir[4][2]= {1,0,-1,0,0,1,0,-1};
int n;
int a[10][10],vis[10][10],want,vv[10][10];
int kk=0;

void checkcolor(int x,int y,int color)
{
    //cout<<11111<<endl;
    //cout<<x<<" "<<y<<endl;
    for (int i=0; i<4; i++)
    {
        int X=x+dir[i][0];
        int Y=y+dir[i][1];
        if (X<0||X>=n||Y<0||Y>=n||vv[X][Y]==1)
        {
            continue;
        }
        if (a[X][Y]==color||vis[X][Y]==1)  //如果颜色相同就将Vis标记为1
        {
            vv[X][Y]=vis[X][Y]=1;  //标记为相连
            checkcolor(X,Y,color);  //继续搜,直到没有相同颜色
        }
        else
            vis[X][Y]=2;  //到不相同的颜色,直接标记为相邻
    }
}

int get_cnt(int color)//将相同颜色的方块连通起来
{
    int t=0;
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
        {
            if (a[i][j]==color&&vis[i][j]==2)
            {
                t++;//记录有多少块已经和左上角相连
                //checkcolor(i,j,color);//将vis的值不断更新
            }
        }
    }
    return t;
}

int get_h()//估价函数,最理想状态下可能最优解,忽略一切外界条件
{
    int ans=0;
    int flag[10];
    memset(flag,0,sizeof(flag));
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
        {
            if (!flag[a[i][j]]&&vis[i][j]!=1)//vis!=1去掉左上角,以防下面重新加
            {
                ans++;
                flag[a[i][j]]=1;
            }
        }
    }
    return ans;
}

int IDA(int dep)//传过来为我现在已经走了的步数
{
    if (dep+get_h()>want)//如果我已经走的步数+估价函数中最好的值>我想要的,那就直接return。
        return false;
    if (dep==want)//如果找到我已经走的等于我的想要的就ok
        return true;
    for (int i=0; i<6; i++)
    {
        int tmp[10][10];
        memcpy(tmp,vis,sizeof(vis));
        if (get_cnt(i))//判断当前颜色是否可以相连,合并到左上角一个块中
        {
            memset(vv,0,sizeof(vv));
            checkcolor(0,0,i);
            if (IDA(dep+1))
               {
                   return true;
               }
        }
        memcpy(vis,tmp,sizeof(vis));
    }
    return false;
}

int main()
{
    while (~scanf("%d",&n))
    {
        if (n==0)
            break;
        for (int i=0; i<n; i++)
        {
            for (int j=0; j<n; j++)
                scanf("%d",&a[i][j]);
        }
        memset(vis,0,sizeof(vis));
        vis[0][0]=1;
        memset(vv,0,sizeof(vv));
        checkcolor(0,0,a[0][0]);
        want=get_h();
        //cout<<want<<endl;
        while (true)
        {
            if (IDA(0))
                break;
            want++;
        }
        printf ("%d\n",want);
    }
    return 0;
}



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值