BZOJ 3041 水叮当的舞步

Posted 神犇(shenben)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3041 水叮当的舞步相关的知识,希望对你有一定的参考价值。

 

3041: 水叮当的舞步

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 120  Solved: 67
[Submit][Status][Discuss]

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

HINT

 

Source

 

题解:

IDA*

比较简单的A* 估价函数很简单就是除了左上角的联通快之外的不同的个数
加上迭代,dfs就好了

10s时间很宽裕

AC代码:

(codevs80-90分)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline const int read(){
    register int x=0,f=1;
    register char ch=getchar();
    while(ch<\'0\'||ch>\'9\') ch=getchar();
    return ch-\'0\';
}
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
const int N=9;
int n,g[N][N],a[N][N];
bool flag,vis[N][N],mark[N]; 
inline void calc(int &c){
    memset(mark,0,sizeof mark);
    c=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(!mark[a[i][j]]){
                mark[a[i][j]]=1;
                c++;
            }
        }
    }
}
void go(int x,int y,int c,int r){
    a[x][y]=r;
    vis[x][y]=1;
    for(int i=0;i<4;i++){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(!vis[nx][ny]&&nx>0&&nx<=n&&ny>0&&ny<=n&&a[nx][ny]==c){
            go(nx,ny,c,r);
        }
    }
}
void get_round(int x,int y,int c,int round[]){
    vis[x][y]=1;
    for(int i=0;i<4;i++){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(!vis[nx][ny]&&nx>0&&nx<=n&&ny>0&&ny<=n){
            if(a[nx][ny]==c) get_round(nx,ny,c,round);
            else if(!round[a[nx][ny]]) round[a[nx][ny]]=1;
        }
    }
}
void dfs(int now,int sum){
    if(flag) return ;
    int C;
    calc(C);
    if(now==sum){
        if(C==1) flag=1;
        return ;
    }
    if(now+C-1>sum) return ;
    memset(vis,0,sizeof vis);
    int round[N]={0};
    get_round(1,1,a[1][1],round);
    for(int i=0;i<=5;i++){
        if(i==a[1][1]||!round[i]) continue;
        int back[N][N];
        memcpy(back,a,sizeof a);
        memset(vis,0,sizeof vis);
        go(1,1,a[1][1],i);
        if(flag) return ;
        dfs(now+1,sum);
        memcpy(a,back,sizeof back);
    }
} 
int main(){
    for(;;){
        n=read();
        if(!n) break;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                g[i][j]=read();
            }
        }
        int ans=0;
        for(int k=0;k<=16;k++){
            memcpy(a,g,sizeof g);
            flag=0;
            dfs(0,k);
            if(flag){
                ans=k;
                break;
            }
        }
        printf("%d\\n",ans);
    }
    return 0;
}

 

以上是关于BZOJ 3041 水叮当的舞步的主要内容,如果未能解决你的问题,请参考以下文章

codevs2495 水叮当的舞步(IDA*)

水叮当的舞步 深搜

codevs2495 水叮当的舞步

codevs 2495 水叮当的舞步

codevs 2495 水叮当的舞步IDA*

codevs2495水叮当的舞步