【NOIP2013模拟】水叮当的舞步

1 篇文章 0 订阅
1 篇文章 0 订阅

题目

水叮当得到了一块五颜六色的格子形地毯作为生日礼物,更加特别的是,地毯上格子的颜色还能随着踩踏而改变。
为了讨好她的偶像虹猫,水叮当决定在地毯上跳一支轻盈的舞来卖萌~~~
地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。
水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,地毯左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。
由于水叮当是施展轻功来跳舞的,为了不消耗过多的真气,她想知道最少要多少步才能把所有格子的颜色变成一样的。

分析

我们迭代加深,枚举答案限制,
BFS枚举每次选择哪种颜色,当枚举次数超过限制,就退出。否则如果BFS出答案就输出。
这样只能拿10分,
加上IDA*,估价函数为图中大颜色数减一,
当枚举的深度加上估价函数大于限制就退出,
接着发现在枚举左上角所在的联通快时很浪费时间,
我们用一个一个N*N的v标记数组。左上角的格子所在的联通块里的格子为1,左上角联通块周围一格的格子为2,其它格子都为为0。如果某次选择了颜色c,我们只需要找出标记为2并且颜色为c的格子,向四周扩展,再修改v标记,就可以不断修改标记,但所有格子都为1,就是答案了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
const int maxlongint=2147483647;
using namespace std;
int n,m,ans;
int z1[4][2]={{1,0},{0,1},{-1,0},{0,-1}},f,a[9][9],t;
int mark[9][9];
bool colour[6];
int makeh()
{
    int h1=0;
    memset(colour,true,sizeof(colour));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if((mark[i][j]!=1 && colour[a[i][j]])) 
            {
                colour[a[i][j]]=false;
                h1++;
            }
        }
    return h1;
}
void put(int x,int y,int z)
{
    mark[x][y]=1;
    for(int i=0;i<=3;i++)
    {
        int xx=x+z1[i][0],yy=y+z1[i][1];
        if((xx<1 || yy<1 || xx>n || yy>n || mark[xx][yy]==1)) continue;
            if(a[xx][yy]==z)
                put(xx,yy,z);
            else
                mark[xx][yy]=2;
    }
}
bool q(int color)
{
    bool p=false;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if((mark[i][j]==2 && a[i][j]==color))
            {
                p=true;
                put(i,j,color);
            }
        }
    return !p;
}
void dg(int g)
{
    int h=makeh();
    if(!h) 
    {
        t=true;
        return;
    }
    if(g+h>f) return;
    int copy1[9][9];
    memcpy(copy1,mark,sizeof(copy1));
    for(int color=0;color<=5;color++)
    {
        if(!q(color) && !t)
            dg(g+1);
        memcpy(mark,copy1,sizeof(mark));
    }
}
int main()
{
    while(1)
    {
        scanf("%d",&n);
        if(!n) break;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&a[i][j]);
            }
        memset(mark,0,sizeof(mark));
        put(1,1,a[1][1]);
        for(f=0;;f++)
        {
            t=0;
            dg(0);
            if(t)
                break;
        }   
        printf("%d\n",f);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值