【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组数据。

题解
IDA*枚举步数进行搜索,用剩余几种颜色做比较函数,为加速搜索,预处理左上角联通快的边界位置,向外扩展。

代码by hzwer

#include<bits/stdc++.h>
typedef long long ll;
const int N=10000000;
const int mod=1000000007;
const double eps=0.00000001;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int step,n,mp[9][9],flag[9][9];
int xx[4]={1,-1,0,0},yy[4]={0,0,-1,1},used[6];
bool ans;
int get()
{
    int ans=0;
    memset(used,0,sizeof(used));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!used[mp[i][j]]&&flag[i][j]!=1)
            {
                used[mp[i][j]]=1;
                ans++;
            }
    return ans;
}
void dfs(int a,int b,int c)
{
    flag[a][b]=1;
    for (int i=0;i<4;i++)
    {
        int x=a+xx[i],y=b+yy[i];
        if (x<1||x>n||y<1||y>n||flag[x][y]==1) continue;
        flag[x][y]=2;
        if (mp[x][y]==c) dfs(x,y,c);
    }
}
bool fill(int c)
{
    int ans=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            if (flag[i][j]==2&&mp[i][j]==c)
            {
                ans++;
                dfs(i,j,c);
            }
    return ans;
}
void search(int s)
{
    int v=get();
    if (!v) ans=1;
    if (s+v>step||ans) return;
    int tmp[10][10];
    for(int i=0;i<=5;i++)
    {
        memcpy(tmp,flag,sizeof(flag));
        if(fill(i))search(s+1);
        memcpy(flag,tmp,sizeof(flag));
    }
}
int main()
{
    while (1)
    {
        n=read();if (n==0) break;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                mp[i][j]=read(),flag[i][j]=0;
        dfs(1,1,mp[1][1]);
        for (ans=step=0;;step++)
        {
            search(0);
            if (ans){printf("%d\n",step);break;}
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值