poj 1768 Hang or not to hang 离散化+搜索+状态压缩

本文详细介绍了如何解决POJ 1768问题,通过离散化、搜索和状态压缩的方法,找出在最多32个寄存器中,使程序终止的最小命令执行次数。首先建立影响关系图,找到影响JZ寄存器的寄存器,然后进行离散化和状态压缩,枚举初始状态以判断程序是否能终止,避免陷入死循环。
摘要由CSDN通过智能技术生成

题目链接:

http://poj.org/problem?id=1768

题目意思:

给你n种命令,最多32个寄存器,问可能的最少的执行命令次数,使程序终止。

解题思路:

对于不能直接和间接影响JZ中的寄存器的寄存器的状态可以是任意,因为他们每一步都是确定的,最终命令执行的次数与初始状态无关。

所以先找出直接和间接影响JZ中的寄存器的寄存器,由于命令最多只有16个,所以除去STOP和JZ,最多只有14个命令,影响的寄存器最多只有16个。

比如命令 AND a b 则寄存器b能影响a,则将a连一条有向边到b.

建好图后,从JZ中的寄存器出发,用dfs扫一遍,得到的寄存器全部是能影响JZ寄存器的,将这些寄存器离散化处理,得到最多16个寄存器,然后状态压缩,每一位表示一个寄存器。枚举初始化的寄存器的状态。

判断程序能否终止,主要看当前命令下的寄存器状态是否处理过,如果处理过,则程序陷入死循环,不能终止。

遇到无用状态直接跳过,因为他们不影响主要寄存器的状态。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
using namespace std;

/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
bool vis[16][1<<15],vv[32]; //映射后只有这么多的寄存器能影响
int map1[32]; //将状态映射过来
char save[16][10]; //保存命令
int can1[16],can2[16],n,m,ans,ss; //参数
vector<int>jz;
vector<int>hav[32];
int  bin[40]; //将每一个寄存器对应的值保存下来

int cal(char * a) //返回该命令的参数个数
{
   if(!strcmp(a,"NOT")||!strcmp(a,"RANDOM")||!strcmp(a,"JMP"))
         return 1;
   if(!strcmp(a,"STOP"))
         return 0;
   return 2;
}

void dfs(int cur)
{
   for(int i=0;i<hav[cur].size();i++)
   {
      if(vv[hav[cur][i]])
         continue;
      //printf("cur:%d->%d\n",cur,hav[cur][i]);
      vv[hav[cur][i]]=true;
      map1[hav[cur][i]]=m;
      m++;
      dfs(hav[cur][i]);
   }
   return ;
}

void Dfs(int sta,int i,int ss)
{
   if(i>=n)
      return ;
   if(vis[i][sta])
      return ;
   ss++;
   vis[i][sta]=true;
   int T=sta;

   if(!strcmp(*(save+i),"AND"))
   {
      int a=map1[can1[i]],b=map1[can2[i]]; //取出对应的离散化的位置
      if(a==-1||b==-1) //遇到无效状态,直接跳过
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false; //从前往后就不用回溯,因为后面的情况一定比当前坏
         return ;
      }
      int tt=sta;
      int aa=(tt>>a)&1,bb=(tt>>b)&1; //取出两寄存器的数
      if(aa&bb) //运算,并把结果加进去
         tt=tt|bin[a];
      else
         tt=tt-(aa<<a);
      Dfs(tt,i+1,ss);
   }
   else if(!strcmp(*(save+i),"OR"))
   {
      int a=map1[can1[i]],b=map1[can2[i]]; //取出对应的离散化的位置
      if(a==-1||b==-1)
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false;
         return ;
      }
      int tt=sta;
      int aa=(tt>>a)&1,bb=(tt>>b)&1;
      if(aa|bb)
         tt=tt|bin[a];
      else
         tt=tt-(aa<<a);
      Dfs(tt,i+1,ss);
   }
   else if(!strcmp(*(save+i),"XOR"))
   {
      int a=map1[can1[i]],b=map1[can2[i]]; //取出对应的离散化的位置
      if(a==-1||b==-1)
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false;
         return ;
      }
      int tt=sta;
      int aa=(tt>>a)&1,bb=(tt>>b)&1;
      if(aa^bb)
         tt=tt|bin[a];
      else
         tt=tt-(aa<<a);
      Dfs(tt,i+1,ss);
   }
   else if(!strcmp(*(save+i),"NOT"))
   {
      int a=map1[can1[i]];
      if(a==-1)
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false;
         return ;
      }
      sta=sta^bin[a]; //取反
      Dfs(sta,i+1,ss);
   }
   else if(!strcmp(*(save+i),"MOV"))
   {
      int a=map1[can1[i]],b=map1[can2[i]];
      if(a==-1||b==-1)
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false;
         return ;
      }
      int aa=(sta>>b)&1;
      if(aa)
         sta=sta|bin[a];
      else
         sta=sta&((bin[m]-1)-bin[a]); //把第a个寄存器清零
      Dfs(sta,i+1,ss);
     // vis[i][sta]=true;
   }
   else if(!strcmp(*(save+i),"SET"))
   {
      int a=map1[can1[i]],b=can2[i];
      if(a==-1)
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false;
         return ;
      }
      if(b)
         sta=sta|(1<<a);
      else
         sta=sta&((bin[m]-1)-bin[a]);
      Dfs(sta,i+1,ss);
     // vis[i][sta]=true;
   }
   else if(!strcmp(*(save+i),"JMP"))
   {
      int a=can1[i];
      Dfs(sta,a,ss);
   }
   else if(!strcmp(*(save+i),"JZ"))
   {
      int a=can1[i],b=map1[can2[i]];
      int bb=(sta>>b)&1; //一定是影响寄存器
      if(!bb)
      {
         Dfs(sta,a,ss);
         vis[i][sta]=false;
         return ;
      }
      Dfs(sta,i+1,ss);
   }
   else if(!strcmp(*(save+i),"STOP"))
   {
      if(ss<ans)
         ans=ss;
   }
   else if(!strcmp(*(save+i),"RANDOM"))
   {
      int a=map1[can1[i]];
      if(a==-1)
      {
         Dfs(sta,i+1,ss);
         vis[i][sta]=false;
         return ;
      }
      Dfs(sta|bin[a],i+1,ss); //置1
      Dfs(sta&(bin[m]-1-bin[a]),i+1,ss); //置0
   }
   vis[i][T]=false;
}
int main()
{
   //printf("%d\n",((1<<31)-1));
   for(int i=0;i<=35;i++)
      bin[i]=(1<<i);
   while(scanf("%d",&n)!=EOF)
   {
      memset(map1,-1,sizeof(map1));
      memset(vv,false,sizeof(vv));

      jz.clear();
      for(int i=0;i<32;i++)
         hav[i].clear();
      for(int i=0;i<n;i++)
      {
          scanf("%s",save+i);
          int t=cal(*(save+i));
          if(t==1)
             scanf("%d",&can1[i]);
          else if(t==2)
          {
             scanf("%d%d",&can1[i],&can2[i]);
             if(!strcmp(*(save+i),"JZ"))
             {
                jz.push_back(can2[i]);  //从这点开始扫描有影响的状态
                continue;
             }
             if(strcmp(*(save+i),"SET"))    //set命令不影响
                hav[can1[i]].push_back(can2[i]);  //寄存器2能影响寄存器1
          }
      }
      m=0; //有效的寄存器,能影响的
      for(int i=0;i<jz.size();i++) //反向扫描能影响的所有寄存器
      {
         if(!vv[jz[i]])
         {
            map1[jz[i]]=m;
            m++;
            vv[jz[i]]=true;
            dfs(jz[i]);
         }
      }
     // printf("m:%d\n",m);
      ans=INF;

      memset(vis,false,sizeof(vis));
     /* for(int i=bin[m]-1;i>=0;i--) //枚举初始状态
         Dfs(i,0,0); //从第0步开始执行*/ //这样写要回溯
         for(int i=0;i<=bin[m]-1;i++)
            Dfs(i,0,0); //这样写不用回溯
      //for(int i=0;i<)
      if(ans==INF)
         printf("HANGS\n");
      else
         printf("%d\n",ans);
   }
   return 0;
}

/*
4
AND 0 1
JZ 1 0
RANDOM 1
STOP

1
AND 0 1

4
SET 0 1
SET 1 1
NOT 1
STOP

2
JMP 1
JMP 0

5
RANDOM 0
JZ 4 0
ADD 0 1
ADD 0 2
STOP

3
SET 0 1
RANDOM 0
RANDOM 1

11
XOR 0 2
SET 0 0
NOT 0
JZ 5 0
JMP 2
AND 1 3
SET 1 1
JZ 10 1
RANDOM 1
JMP 7
STOP

5
SET 0 1
JZ 4 0
RANDOM 0
JMP 1
STOP


ans:HANGS
ans:14
ans:6

3
RANDOM 0
AND 1 0
STOP
HANGS

*/
/*
1
AND 0 1
m:0
HANGS
3
RANDOM 0
AND 1 2
STOP
m:0
3
1
AND 0 1
m:0
3
*/ //这很奇怪,为什么不一样呢,初始化都弄好了啊





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值