吴昊品游戏核心算法 Round 7(特刊)—— 猜数字系列(数字锁问题) 第三弹(模拟)(HDOJ 1195)

 如图所示,这是一个保险箱,木有错,我们现在假设该密码有四位数,我们也知道密码的存在,我们可以基于以下的规则对这个四位数进行一系列变换,比如:

  (1)可以将这个四位数的某一位上移或者下移,其中,9再往上移动便是0,而0再往下移动即是9。

  (2)两个相邻的数位是可以交换(change)的,但是,有如下规则,最左边的数位不能和最右边的数位发生交换,也就是说,这两个数位,不认为是相邻的。

  我们基于(1)和(2)这两个规则,要找出打开锁(也就是找到密码)需要移动的最少的次数——这里的AI,我们采用宽度优先搜索来实现(BFS+STL,可以看到,这已经是重复多遍的老战术了!对于搜索来说,这种策略确实是相当普遍的)。

  问题来自HDOJ 1195,我以这个问题作为猜数字系列的完结篇。

  

  1 /*
  2     Highlights:
  3    (1)用mark[11][11][11][11]存储四位数,可以方便对其进行调控
  4    (2)在BFS的过程中,对于四位数的每一位,每次朝着三个可能的方向对其进行搜索,并适时标记可能的点
  5    (3)初始的时候,需要判断一下是否一开始就满足条件
  6  */
  7  
  8  #include<iostream>
  9  #include<string>
 10  #include<queue>
 11  using namespace std;
 12  
 13  struct node
 14  {
 15    char digit[5];//数组尽量开大一点
 16    int step;//记录次数       
 17  };
 18  
 19  int mark[11][11][11][11];
 20  char a[5],b[5];
 21  
 22  void bfs()
 23  {
 24    int i;
 25    node cur,q;
 26    queue<node> Queue;
 27    strcpy(q.digit,a);//将数字锁的初始值装载到q中
 28    q.step=0;//初始步骤为0
 29    Queue.push(q);
 30    memset(mark,0,sizeof(mark));//将mark置0,从0开始搜索
 31    while(!Queue.empty())
 32    {
 33      cur=Queue.front();//现在的结点
 34      Queue.pop();
 35      mark[cur.digit[0]-'0'][cur.digit[1]-'0'][cur.digit[2]-'0'][cur.digit[3]-'0']=1;
 36      //四个位数
 37      for(i=0;i<4;i++)
 38      {
 39        //加一尝试
 40        strcpy(q.digit,cur.digit);
 41        q.step=cur.step+1;
 42        q.digit[i]=cur.digit[i]+1;
 43        if(q.digit[i]='9'+1)
 44        {
 45          q.digit[i]='1';                    
 46        }
 47        //'0'表示还没有被visit的点,'1'表示已经标记过的点                
 48        if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
 49        {
 50          if (strcmp(q.digit, b) == 0)
 51          {
 52            printf("%d/n", q.step);
 53            return;
 54          }
 55          else
 56          {
 57            mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
 58            Queue.push(q);//进入队列
 59          }    
 60      }                     
 61      //减一尝试
 62      strcpy(q.digit, cur.digit);
 63      q.step = cur.step + 1;
 64      q.digit[i] = cur.digit[i] - 1;
 65      if (q.digit[i] == '0')
 66      {
 67        q.digit[i] = '9';
 68      }
 69      if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
 70      {
 71        if (strcmp(q.digit, b) == 0)
 72        {
 73          printf("%d/n", q.step);
 74          return;
 75        }
 76        else
 77        {
 78          mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
 79          Queue.push(q);
 80         }
 81      }
 82      //交换尝试,由于不需要考虑首尾变换,故i<3就可以的
 83      if (i < 3)
 84      {
 85        strcpy(q.digit, cur.digit);
 86        char temp = q.digit[i];//类似于两个数交换,这里有交换数组中相邻元素的值
 87        q.digit[i] = q.digit[i + 1];
 88        q.digit[i + 1] = temp;
 89        q.step = cur.step + 1;
 90        if (mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] == 0)
 91        {
 92          if (strcmp(q.digit, b) == 0)
 93          {
 94            printf("%d/n", q.step);
 95            return;
 96          }
 97          else
 98          {
 99            mark[q.digit[0] - '0'][q.digit[1] - '0'][q.digit[2] - '0'][q.digit[3] - '0'] = 1;
100            Queue.push(q);
101          }
102        }
103      }
104    }       
105  }
106  
107  void main()
108  {
109    int n;
110    scanf("%d",&n);//读取样例的个数
111    while(n--)
112    {
113      scanf("%s%s",a,b);
114      //运气好,刚好相等!
115      if(strcmp(a,b)==0)
116        printf("0\n");
117      else
118        bfs();          
119    }    
120  }
121 

posted on 2013-02-27 21:23  吴昊系列  阅读(219)  评论(0编辑  收藏  举报

导航