zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    提高情商的八种方法
    线程安全与可重入
    【Linux必知必会】initrd.img、vmlinux和 vmlinuz************
    shell调试技术
    (转)DeviceIOControl详解
    软件质量特性及其子特性列表
    【Linux必知必会】initrd.img、vmlinux和 vmlinuz
    驱动程序与应用程序之间共享内存
    调试器GDB
    知道IP地址和子网掩码。算出网络地址、广播地址、地址范围、可用的主机数
  • 原文地址:https://www.cnblogs.com/shenben/p/5823304.html
Copyright © 2011-2022 走看看