[NOIP2017模拟]玩积木

2017.10.16 T2 1984

样例数据
输入

1
1
2 0
2 1 2
3 3 3 3
4 4 4 4 4
5 5 5 5 5 5

输出

3

分析:如果这道题硬跑dfs,emmmm, 420 次绝对炸(当然前50%还是能拿的)。考试的时候想正反两个dfs(一个是原图走10次,一个是读入的图走10次),将正dfs放到hash表中,看反dfs能否在10次内找到hash值,如果能就可以输出dep1+dep2,但是没能调出来orz(hash表果然玄学)。 其实这是一个正解,气
另一种方法也很玄学,那就是A*剪枝(一种提前判断并排除不优路径的方法,写出来的程序快慢与否取决于选手剪枝判断函数够不够优秀),但是对于这道题的数据,跑的那个快啊……

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

const int org[7][7]={0,0,0,0,0,0,0,//直接预处理原图
                     0,0,0,0,0,0,0,
                     0,1,1,0,0,0,0,
                     0,2,2,2,0,0,0,
                     0,3,3,3,3,0,0,
                     0,4,4,4,4,4,0,
                     0,5,5,5,5,5,5};
const int fx[5]={0,-1,1,-1,1};
const int fy[5]={0,-1,0,0,1};
int T,bjx,bjy,ans;
int a[7][7];
bool bjans;

int Ax()//判断函数:比对原图和现在的图,看还有多少个不同,也就是至少还需要走多少步
{
    int res=-1;//因为两个位置不同最少一步(它俩互换),同理n个位置不同最少n-1步,所以刚开始res=-1
    for(int i=1;i<=6;++i)
        for(int j=1;j<=i;++j)
            if(a[i][j]!=org[i][j])
                res++;

    return res;
}

void dfs(int dep,int x,int y)
{
    if(Ax()==-1)//A*剪枝1:已经全部配好,更新答案,回退
    {
        ans=min(ans,dep);
        bjans=1;
        return;
    }
    if(Ax()+dep>ans)//A*剪枝2:至少需要走的和已经走的加起来超过ans,便不是最优值了,回退
        return;
    if(x>ans-dep)//A*剪枝3:0所在的层数比还能走的步数还大,也就是0现在根本无法返回到第一层,回退
        return;

    for(int i=1;i<=4;++i)//正常的dfs
    {
        int newx=x+fx[i];
        int newy=y+fy[i];
        if(newx>=1&&newx<=6&&newy>=1&&newy<=newx)
        {
            swap(a[x][y],a[newx][newy]);
            dfs(dep+1,newx,newy);
            swap(a[x][y],a[newx][newy]);
        }
    }
}

int main()
{
    freopen("blocks.in","r",stdin);
    freopen("blocks.out","w",stdout);

    T=getint();
    while(T--)
    {
        for(int i=1;i<=6;++i)
            for(int j=1;j<=i;++j)
            {
                a[i][j]=getint();
                if(a[i][j]==0)
                    bjx=i,bjy=j;
            }

        ans=20,bjans=0;//赋初值
        dfs(0,bjx,bjy);

        if(bjans)
            cout<<ans<<'\n';
        else
            cout<<"too difficult"<<'\n';
    }
    return 0;
}

本题结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值