POJ-1768:Hang or not to hang(bfs+一些特殊优化)


题目链接:点击打开链接


题目大意:

主人公写了一段程序,这些程序会对一些迭代器进行操作,使迭代器的值发生变化,问你最后程序能否结束,如果能结束,输出最小步数。


解题思路:

淦,这道题坑了我整整一天。刚开始写出来以后,各种wa,后来发现了一个超级严重的bug,改了以后继续wa,然后wa了一上午加一下午后,突然队友发现每个迭代器的初始值是随机的,我= = ,tm比赛的时候队友还问我这道题有没有什么坑,我看了看题说注意迭代器初始值随机结果补题的时候就他喵忘了。。。说一下自己解这道题的思路历程(其实是wa的历程),希望对大家有所帮助。

首先这道题的迭代器有32个,当时比赛的时候就卡在了这里,不知道怎么优化内存。知道题目上说的最多16个步骤肯定有用就是不知道哪有用。赛后就发现了,我他喵一共16步,那么多迭代器有屁用。然而这里就犯下了一个严重的错误

因为刚开始我默认所有迭代器的值都是0,所以我上来是默认只有a迭代器是有用的,所以我状态里只存了a迭代器,理论上来说如果所有迭代器的初始值都是0的话其实这种思路应该是对的,然而迭代器默认值并不是0,遂wa了将近一天。

发现初始值的问题后,就意识到貌似有点问题,因为初始值随机的话,意味着bfs过程中你的初始状态要将所有的可能状态加入队列,那么就要考虑b迭代器了,那么我存的迭代器数量就可能大大增加,最坏情况貌似还是32个。刚开始还抱着侥幸心理,以为说不定a,b迭代器合起来也就那么多,结果一次RE,一次MLE告诉我,我想多了。

然后就迷茫了,感觉这道题又回到了起点。不知道该怎么做,实在没办法了,去查了大神的博客,然后我真是膜拜了。

其实这道题优化的关键点在于JZ,因为JZ那一步的跳跃是跟a迭代器有关的,其他的步骤除了跟(a迭代器或者间接跟a迭代器有关的迭代器)相关的步骤需要进行操作,其他无关的迭代器直接走就是了,管你的值是多少,程序跟你又没有关系,语文太烂了,表述不清,举个例子,例如

AND a b

XOR b c(理论上来说应该是 写成 a,b形式的,这里b,c指迭代器的种类)

SET d 0

JZ 1 a

STOP

大家看上面这个例子,整个程序的运行步骤跟d迭代器的值有关吗?d迭代器值是多少对程序怎么运行应该没影响吧,相反a迭代器跟JZ能否跳跃相关,那么跟a迭代器相关的迭代器比如 b c的值都是有用的,就这样就可以做到只把需要的迭代器取出来储存状态进行操作,遇到没有用的迭代器直接进入下一步骤即可。

做到这一步的话其实就是用vector建个树,先将所有JZ的迭代器先存入,然后再和他们相关的迭代器建个有向边,其实就是类似树的结构,深搜一遍得到所有有用的迭代器即可。而且这些迭代器和起来不会很多,为啥呢,大家自己想吧,

因为之前写过错误的程序,所以稍微就这样修改了一下最终终于AC,这道题简直了,感动到QAQ。。。

写这么多也是希望大家其实最好自己写,毕竟这种代码繁琐的题每个人都有自己的写法,一味看别人代码的话很可能会看不懂吧,毕竟东西太多了,这道题实现也比较复杂,感觉我自己的代码都丑到不行(逃~,

以下代码后面会附带一些数据,当然这些数据是我默认所有迭代器初始值为0做的,最后还会附一个迭代器初始值不是0的数据,希望大家都能成功AC。



#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <set>
#include <functional>
#define retrun return
#define true ture
#define mian main
#define rank ra
#define next ne
#define pb push_back
#define hash haha
#define lson rt<<1
#define rson rt<<1|1
#define xlson xl,xmid,xt<<1
#define xrson xmid+1,xr,xt<<1|1
#define ylson yl,ymid,xt,yt<<1
#define yrson ymid+1,yr,xt,yt<<1|1
using namespace std;
typedef long long ll;
const int N=1<<16;
int n,scp,ans,g1,g2,g3;
char qu[20][10];    //存步骤
int p[20],q[20];    //存每一步对应的迭代器
int ch[40];         //存跟JZ直接相关的迭代器
int ma[40];         //存每个迭代器在二进制中的位置
bool v1[40];        //存哪些迭代器是有用的
vector<int> v[40];  //建树
bool vis[20][N+10]; //存bfs中的状态
struct node
{
    int dog;    //当前状态
    int dir;    //当前步骤
    int step;
};
void bfs()
{
    memset(vis,0,sizeof vis);
    queue<node> que;
    node st;
    st.dir=1;
    st.step=1;
    for(int i=0;i<=(1<<g1);i++) //将所有初始值的可能状态加入队列
    {
        st.dog=i;
        que.push(st);
        vis[1][st.dog]=1;
    }
    node k1;
    ans=-1;
    while(!que.empty())
    {
        node k=que.front();
        que.pop();
        if(k.dir>n) //超过步骤
            continue;
        if(qu[k.dir][0]=='S'&&qu[k.dir][1]=='T')    //结束状态
        {
            ans=k.step;
            break;
        }
        int a,b;
        int g=k.dir;
        if(qu[g][0]=='J'&&qu[g][1]=='M')    //无条件跳跃
        {
            k1.dir=p[g]+1;
            k1.dog=k.dog;
            k1.step=k.step+1;
            if(vis[k1.dir][k1.dog]==0)
            {
                que.push(k1);
                vis[k1.dir][k1.dog]=1;
            }
            continue;
        }
        if(qu[g][0]=='J'&&qu[g][1]=='Z')
        {
            a=((k.dog>>(ma[q[g]]))%2);
            if(a==0)
                k1.dir=p[g]+1;
            else
                k1.dir=k.dir+1;
            k1.dog=k.dog;
            k1.step=k.step+1;
            if(vis[k1.dir][k1.dog]==0)
            {
                que.push(k1);
                vis[k1.dir][k1.dog]=1;
            }
            continue;
        }
        if(v1[p[g]]==0)     //遇到无用迭代器直接下一步
        {
            k1.dir=k.dir+1;
            k1.dog=k.dog;
            k1.step=k.step+1;
            if(vis[k1.dir][k1.dog]==0)
            {
                que.push(k1);
                vis[k1.dir][k1.dog]=1;
            }
            continue;
        }
        if(qu[g][0]=='R')   //随机迭代器的值 注意位运算
        {
            k1.dir=k.dir+1;
            k1.step=k.step+1;
            a=scp^(1<<ma[p[g]]);
            k1.dog=k.dog&a;
            if(vis[k1.dir][k1.dog]==0)
            {
                que.push(k1);
                vis[k1.dir][k1.dog]=1;
            }
            k1.dog=k.dog|(1<<(ma[p[g]]));
            if(vis[k1.dir][k1.dog]==0)
            {
                que.push(k1);
                vis[k1.dir][k1.dog]=1;
            }
            continue;
        }
        a=((k.dog>>(ma[p[g]]))%2);  //得到当前对应的a b迭代器的值
        b=((k.dog>>(ma[q[g]]))%2);
        if(qu[g][0]=='A')
            a=(a&b);
        if(qu[g][0]=='O')
            a=(a|b);
        if(qu[g][0]=='X')
            a=a^b;
        if(qu[g][0]=='N')
            a=a^1;
        if(qu[g][0]=='M')
            a=b;
        if(qu[g][0]=='S'&&qu[g][1]=='E')
            a=q[g];
        if(a==0)
        {                           //注意位运算的过程
            a=scp^(1<<ma[p[g]]);
            k1.dog=k.dog&a;
        }
        if(a==1)
            k1.dog=k.dog|(1<<(ma[p[g]]));
        k1.dir=k.dir+1;
        k1.step=k.step+1;
        if(vis[k1.dir][k1.dog]==0)
        {
            que.push(k1);
            vis[k1.dir][k1.dog]=1;
        }
    }
    if(ans==-1)
        printf("HANGS\n");
    else
        printf("%d\n",ans);
}
void dfs(int k)     //深搜树
{
    for(int i=0;i<(int)v[k].size();i++)
    {
        if(v1[v[k][i]]==0)
        {
            v1[v[k][i]]=1;
            ma[v[k][i]]=g1++;
            dfs(v[k][i]);
        }
    }
}
void init()
{
    memset(v1,0,sizeof v1);
    g1=0;scp=(1<<17)-1;
    for(int i=1;i<=g3;i++)
    {
        if(v1[ch[i]]==0)
        {
            v1[ch[i]]=1;
            ma[ch[i]]=g1++;
            dfs(ch[i]);
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(p,-1,sizeof p);
        memset(q,-1,sizeof q);
        memset(ma,-1,sizeof ma);
        memset(qu,0,sizeof qu);
        for(int i=1;i<=40;i++)
            v[i].clear();
        g3=0;
        for(int i=1;i<=n;i++)
        {
            scanf(" %s",qu[i]);
            if(qu[i][0]=='S'&&qu[i][1]=='T')
                continue;
            if(qu[i][0]=='R'||qu[i][0]=='N'||(qu[i][0]=='J'&&qu[i][1]=='M'))
                scanf("%d",&p[i]);
            else
                scanf("%d%d",&p[i],&q[i]);
            if(qu[i][0]=='J'&&qu[i][1]=='M')
                continue;
            if(qu[i][0]=='J')
                ch[++g3]=q[i];  //存所有跟JZ直接相关的迭代器
            else if(qu[i][0]=='S'||qu[i][0]=='N'||qu[i][0]=='R');   //注意分号
            else
                v[p[i]].pb(q[i]);   //建立有向边
        }
        init();
        bfs();
    }
}       //运行答案应该是 13 18 2
/*
12
SET 0 0
SET 1 1
JZ 6 1
SET 2 1
RANDOM 1
JMP 2
SET 2 1
JZ 11 2
SET 0 1
RANDOM 2
JZ 7 2
STOP

16
SET 0 0
SET 1 0
SET 2 0
MOV 1 0
MOV 2 1
XOR 1 0
NOT 1
JZ 15 1
RANDOM 0
MOV 2 0
JZ 12 0
NOT 2
NOT 1
JZ 5 1
JMP 0
STOP

2
JZ 0 0
STOP
*/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值