【NOIP2011】Mayan游戏 搜索

题目有图,不附了

这个题的步数最大才5步,目测直接暴力搜即可,除了各种细节恶心人之外,其实不是很难,虽然我打了半天…

bfs。

关于剪枝:
1:可行性剪枝。若当前某种颜色的方块只有1或2个,则剪掉。
2:最优性剪枝。如果某三行中某个颜色的方块[x1,y1]只会出现一次,则cnt++,跳一行继续搜。设给定的步数为n,若cnt+step>n则剪枝。

然而我的最优性剪枝并没有什么效果…时间总共大概3000+ms

当然我觉得没有必要交换两个颜色相同的方块

看SHY的题解,她的最优性剪枝是这样:
若某一行中存在某一种颜色,它只有1个或2个方块,则他必须借助其它行来帮助消除,设离当前行最近且含有当前颜色的行与当前行的距离是K,求出对于所有方块最大的maxk,则maxk就是消除全部方块的下界,如果step+maxk>n大,则剪枝。

不过测试了一下,把我的最优性剪枝换成SHY的,时间变成4600+ms…………

这里是代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;

struct sta{
    int map[7][8];
    int x[7],y[7],g[7],step;
    int hash;
    sta()
    {
        memset(map,0,sizeof(map));
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memset(g,0,sizeof(g));
        step=0;
        hash=0;
    }
}f;
int step;

bool checkend(const sta &a)
{
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=7;j++)
        {
            if(a.map[i][j]) return false;
        }
    }
    return true;
}
bool hash[10000010];
void gethash(sta &a)
{
    int mod=10000007;
    int ans=0;
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=7;j++)
        {
            ans=( (ans%mod*10)%mod + a.map[i][j]%mod )%mod;
        }
    }
    a.hash=ans;
}

void fall(sta &a)
{
    for(int i=1;i<=5;i++)
    {
        int tot=1;
        for(int j=1;j<=7;j++)
        {
            if(a.map[i][j])
            {
                a.map[i][tot]=a.map[i][j];
                tot++;
            }
        }
        for(int j=tot;j<=7;j++) a.map[i][j]=0;
    }
}

const int dx[]={0,-1,1,0,0};
const int dy[]={0,0,0,1,-1};

int r[20][20],c[20][20];
bool change(sta &a)
{
    memset(r,0,sizeof(r));
    memset(c,0,sizeof(c));
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=7;j++)
        if(a.map[i][j])
        {
            if(a.map[i][j]==a.map[i][j+1]&&a.map[i][j]==a.map[i][j+2])
            {
                r[i][j]=r[i][j+1]=r[i][j+2]=a.map[i][j];
            }
            if(a.map[i+1][j]==a.map[i][j]&&a.map[i][j]==a.map[i+2][j])
            {
                c[i][j]=c[i+1][j]=c[i+2][j]=a.map[i][j];
            }           
        }
    }
    bool flag=0;
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=7;j++)
        {
            if(r[i][j]||c[i][j]) {a.map[i][j]=0;flag=1;}
        }
    }   
    return flag;
}

int t[20];

bool check(const sta &a)
{
    memset(t,0,sizeof(t));
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=7;j++)
        {
            if(a.map[i][j])
            {
                t[a.map[i][j]]++;
            }
        }
    }
    bool flag=1;
    for(int i=1;i<=10;i++)
    {
        if(t[i]) flag=0;
        if(t[i]>=3) return true;
    }
    if(flag) return true;
    return false;
}

bool vis[12][12];

bool checkhaha(const sta &a,int x,int y)
{
    for(int i=x-1;i<=x+1;i++)
    {
        for(int j=1;j<=7;j++)
        {
            if(i==x&&j==y) continue;
            if(a.map[x][y]==a.map[i][j]) return false;
        }
    }
    return true;
}

int h(const sta &a)
{
    memset(vis,0,sizeof(vis));
    int ans=0;
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=7;j++)
        {
            if(a.map[i][j]&&!vis[i-1][j]&&checkhaha(a,i,j)) {vis[i][j]=1,ans++;i++;}
        }
    }
    return ans;
}

queue<sta> q;
void bfs()
{
    f.step=0;
    gethash(f); 
    q.push(f);
    while(q.size())
    {
        f=q.front(); q.pop();
        if(checkend(f))
        {
            for(int i=1;i<=f.step;i++)
            {
                printf("%d %d %d\n",f.x[i]-1,f.y[i]-1,f.g[i]);  
            }
            return ;
        }
        if(f.step==step) continue;
        for(int i=1;i<=5;i++)
        {
            for(int j=1;j<=7;j++)
            {
                if(f.map[i][j])
                {
                    if(i+1<=5&&f.map[i][j]!=f.map[i+1][j])
                    {
                        sta nxt=f;
                        swap(nxt.map[i][j],nxt.map[i+1][j]);
                        nxt.step++;
                        nxt.x[nxt.step]=i;
                        nxt.y[nxt.step]=j;
                        nxt.g[nxt.step]=1;
                        fall(nxt);
                        while(change(nxt)) fall(nxt);
                        gethash(nxt);                   

                        if(!hash[nxt.hash]&&check(nxt)&&h(nxt)+nxt.step<=step)
                        {
                            q.push(nxt);hash[nxt.hash]=1;
                        }
                    }   
                    if(i-1>0&&f.map[i][j]!=f.map[i-1][j])
                    {
                        sta nxt=f;
                        swap(nxt.map[i][j],nxt.map[i-1][j]);
                        nxt.step++;
                        nxt.x[nxt.step]=i;
                        nxt.y[nxt.step]=j;
                        nxt.g[nxt.step]=-1;
                        fall(nxt);
                        while(change(nxt)) fall(nxt);
                        gethash(nxt);
                        if(!hash[nxt.hash]&&check(nxt))
                        {
                            q.push(nxt);hash[nxt.hash]=1;                                       
                        }
                    }
                }
            }
        }
    }   
    puts("-1");
}


int main()
{
    scanf("%d",&step);
    for(int i=1;i<=5;i++)
    {
        int k,j=1;
        while(~scanf("%d",&k)&&k) f.map[i][j]=k,j++; 
    }
    bfs();
    return 0;
}

删掉注释3500+B,原来有注释是5700B…我还改了好多次……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值