您的位置:首页 > 其它

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

2017-08-29 09:12 267 查看
题目链接:点击打开链接

题目大意:

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

解题思路:

淦,这道题坑了我整整一天。刚开始写出来以后,各种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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: