程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> poj1184 聰明的打字員

poj1184 聰明的打字員

編輯:C++入門知識

L - 聰明的打字員
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit StatusDescription

阿蘭是某機密部門的打字員,她現在接到一個任務:需要在一天之內輸入幾百個長度固定為6的密碼。當然,她希望輸入的過程中敲擊鍵盤的總次數越少越好。
不幸的是,出於保密的需要,該部門用於輸入密碼的鍵盤是特殊設計的,鍵盤上沒有數字鍵,而只有以下六個鍵:Swap0, Swap1, Up, Down, Left, Right,為了說明這6個鍵的作用,我們先定義錄入區的6個位置的編號,從左至右依次為1,2,3,4,5,6。下面列出每個鍵的作用:
Swap0:按Swap0,光標位置不變,將光標所在位置的數字與錄入區的1號位置的數字(左起第一個數字)交換。如果光標已經處在錄入區的1號位置,則按Swap0鍵之後,錄入區的數字不變;
Swap1:按Swap1,光標位置不變,將光標所在位置的數字與錄入區的6號位置的數字(左起第六個數字)交換。如果光標已經處在錄入區的6號位置,則按Swap1鍵之後,錄入區的數字不變;
Up:按Up,光標位置不變,將光標所在位置的數字加1(除非該數字是9)。例如,如果光標所在位置的數字為2,按Up之後,該處的數字變為3;如果該處數字為9,則按Up之後,數字不變,光標位置也不變;
Down:按Down,光標位置不變,將光標所在位置的數字減1(除非該數字是0),如果該處數字為0,則按Down之後,數字不變,光標位置也不變;
Left:按Left,光標左移一個位置,如果光標已經在錄入區的1號位置(左起第一個位置)上,則光標不動;
Right:按Right,光標右移一個位置,如果光標已經在錄入區的6號位置(左起第六個位置)上,則光標不動。
當然,為了使這樣的鍵盤發揮作用,每次錄入密碼之前,錄入區總會隨機出現一個長度為6的初始密碼,而且光標固定出現在1號位置上。當巧妙地使用上述六個特殊鍵之後,可以得到目標密碼,這時光標允許停在任何一個位置。
現在,阿蘭需要你的幫助,編寫一個程序,求出錄入一個密碼需要的最少的擊鍵次數。

Input

僅一行,含有兩個長度為6的數,前者為初始密碼,後者為目標密碼,兩個密碼之間用一個空格隔開。
Output

僅一行,含有一個正整數,為最少需要的擊鍵次數。
Sample Input

123456 654321Sample Output

11搜索的壯態壓縮,其實,左移是沒什麼用的,因為,你大可右移,在右移的時候,就把數值改變了去就可以,因為數值的改變和你光標所在的位置是沒關的,只要,你曾移到過那個位置就可以了,所以,我們可以先把原數的所有的排列求出來,再求出排出後的數列的要移動的步數就可以了,這樣我們先處理012345的所有排列,所要右移和交換的次數,對於其他的任何數,由這個數列進行相對應的變換就可以了!我們開一個visit數組前6個是6個數,最後一個是光標的壯態,我們可以發現,光標的壯態只有10種,這樣用BFS搜索之後,只有不到273種壯態了,大大的壓縮的,搜索的難度,時間自然就不成問題了!


#include<string.h> 
 #include<stdio.h> 
 #include<math.h> 
 #include<iostream> 
 using namespace std; 
 int visit[6][6][6][6][6][6][10],flag[6],maxx,aim[6],start[6]; 
 struct tree{int pos,state,num[6],step;}queue[50000];  
int sign[10][6]=//總共10號位  
{  1,0,0,0,0,0,//0  
1,1,0,0,0,0,//1 
 1,1,1,0,0,0,//2
  1,1,1,1,0,0,//3  
1,1,1,1,1,0,//4  
1,1,1,1,1,1,//5  
1,0,0,0,0,1,//6 
 1,1,0,0,0,1,//7 
 1,1,1,0,0,1,//8 
 1,1,1,1,0,1//9  
}; 
 int findstate(int ss[])
  {      int i,sum;    
  sum=0;    
  for(i=0;i<6;i++)   
   {          if(ss[i]!=0)   
       sum=sum*10+1;    
      else               sum=sum*10;  
    }      i=sum;  
    if(i==100000)      return 0;  
      else if(i==110000)      return 1;   
   else if(i==111000)      return 2;    
  else if(i==111100)      return 3;   
   else if(i==111110)      return 4;    
  else if(i==111111)      return 5;   
   else if(i==100001)      return 6;   
   else if(i==110001)      return 7;  
    else if(i==111001)      return 8;  
    else if(i==111101)      return 9;  
  }  int changestate(int i,int state)//根據幾個狀態的關系,來改變  
{      if(i==0)   
   {          if(state<=4||(state>=6&&state<=8))  
        return state+1;          else if((state==5)||(state==9))  
        return 5;      }    
  else if(i==1)      { 
         if(state<=3)       
   return state+6;          else if(state>=5)   
       return state;      
    else if(state==4)//4號位上交換,就成了5號位      
    return 5;      }      else if(i==2)//和第一號位交換不改變state的狀態   
   return state;    }  void  changnum(int i,int t,int w)  {  
    int * p=queue[t].num,j;      for(j=0;j<6;j++)      {      
    queue[w].num[j]=*(p+j);//先把num的值改變      }  
    if(i==0)//只有交換才改變num 的值,只有交換不改變num的值 
      {         return ;      }      else if(i==1)      {   
    queue[w].num[queue[w].pos]=*(p+5);     
  queue[w].num[5]=*(p+queue[w].pos);//五號位的和當前位的地方交換   
    return;      }      else if(i==2)      {         
 queue[w].num[queue[w].pos]=*(p);       
   queue[w].num[0]=*(p+queue[w].pos);//0號位的和當前位的地方交換  
        return ;  
    }      }  bool visitcan ( int w)  {   
   int * p=queue[w].num ; 
     return visit[*p][*(p+1)][*(p+2)][*(p+3)][*(p+4)][*(p+5)][queue[w].state]; 
     }  int changevisit(int w)  {      int * p=queue[w].num;    
  visit[*p][*(p+1)][*(p+2)][*(p+3)][*(p+4)][*(p+5)][queue[w].state]=1;  
      return 1; 
 }    void bfs()  {      memset(visit,0,sizeof(visit)); 
     int t,w,i,state,pos,step;  
    t=w=1;   
   queue[1].pos=0;   
   for(i=0;i<6;i++)       
   queue[1].num[i]=i;     
 queue[1].state=0;     
 queue[1].step=0;    
  visit[0][1][2][3][4][5][0]=1;   
   while(t<=w)      {          state=queue[t].state;     
     pos=queue[t].pos;          step=queue[t].step;  
       for(i=0;i<=2;i++)//三種操作,右移交6,交1號位     
    {                  w++;     
             if(i==0)//右移          
        {                    
  if(queue[t].pos==5)//到過右邊不能移動  
                    {                       
   w--;                          continue;                      }       
           queue[w].pos=queue[t].pos+1;//光標的位置要加一   
               queue[w].state=changestate(i,state);      
            queue[w].step=step+1;     
             changnum(i,t,w);//右移數值不變          
        if(visitcan(w))                  w--;           
       else                  changevisit(w);     

             }                  else if(i==1)                  {         
             if(queue[t].pos==5)//在5號不用交換             
         {                          w--;       
                   continue;  
                    }                  
  queue[w].pos=queue[t].pos;//交換5號位的光標位置不變    
              queue[w].state=changestate(i,state);        
          queue[w].step=step+1;    
              changnum(i,t,w);           
       if(visitcan(w))                  w--;       
           else     
               changevisit(w);          
          }                  else if(i==2)                  {                
      if(queue[t].pos==0)//在0號不用交換            
          {                          w--;           
               continue;                 
     }                  queue[w].pos=queue[t].pos;//交換0號位的光標位置不變         
         queue[w].state=changestate(i,state);         
         queue[w].step=step+1;            
      changnum(i,t,w);     
             if(visitcan(w))                  w--;          
        else                  changevisit(w);       
             }            }          t++;      }      maxx=w;   
   return ;  
}  void init(int s,int e)//把s和e 分解開來  {      int num=5;   
  while(s)     {         start[num]=s%10;   
      s=s/10; 
      
  num--;       }     num=5;  
   while(e)     {         aim[num]=e%10; 
        num--;         e=e/10;  
   }     return ; 

 }  bool statecan(int ss[],int i)//注意,
不一定是要狀態相等才行,只要搜索到的壯態把要改變的數的壯態可以覆蓋就可以了!
  {        int sss[6],j;      for(j=0;j<6;j++) 
     {          sss[j]=sign[i][j];       
   if((ss[j]==1)&&(sss[j]!=1))              return false;   
    }      return true;    }  int main ()  {   
   int s,e,i,k,j,minx,ans,*p,state,temp[6];   
   bfs();//搜索各種排列的要的步數,不用考慮輸入和輸出的值      
      while(scanf("%d%d",&s,&e)!=EOF)      {           minx=0x4f4f4f4f;     
     init(s,e);//將初始位置進行變換          for(j=0;j<6;j++)       
   temp[j]=start[j];       
   for(i=1;i<=maxx;i++)//枚舉出所有的數列     
     {              ans=0;      
        p=queue[i].num;      
        for(j=0;j<6;j++)//每一輪flag要更新   
           {                  flag[j]=0;           
                    }              state=0;        
                  for(j=0;j<6;j++)       
       {                  k=fabs(temp[*(p+j)]-aim[j]);        
          ans+=k;              
    if(k!=0)          
        {                      flag[j]=1;        
          }                }      
        state=findstate(flag);    
                        if(statecan(flag,queue[i].state))     
         {              ans+=queue[i].step;         
     if(ans<minx)              {              minx=ans;       
                     }              }          }               
         printf("%d\n",minx);       
       }      return 0;  }  

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved