Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5839 | Accepted: 1190 |
Description
不幸的是,出于保密的需要,该部门用于输入密码的键盘是特殊设计的,键盘上没有数字键,而只有以下六个键: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
Output
Sample Input
123456 654321
Sample Output
11
题目大意:给2个数字串,给6种操作,要求最少的步数将第一串变成第二串。6种操作分别是:
1:swap0:光标位置不变,将光标位置数字与第一个数字交换;
2:swap1:光标位置不变,将光标位置数字与第六个数字交换;
3:left:如果光标不在1位置,光标左移一位;
4:right:如果光标不在6位置,光标右移一位;
5:up:光标位置不变,如果光标位置数字小于9,光标位置数字加1,否则不变;
6:down:光标位置不变,如果光标位置数字大于0,光标位置数字减一,否则不变;
思路:6种操作可以分成2类:1-4操作是第一类,能改变初始状态每个数的位置,5-6操作能改变光标所访问到的位置的数。所以我们将改变数值的操作和改变光标位置的操作分离开来,对改变光标位置的操作进行bfs,最后与结果比较,光标经过的位置可以改变大小,每一位的改变数值的操作次数为该状态与目标状态绝对值之和。
oh-sorry ! 忘记说还要考虑光标的访问状态了 光标访问状态有10种 具体见代码 只有被光变访问了的位置的数才能用第二种操作来改变大小
ps:这题网上很多题解 都说左移是不必要的 但是左移是必须的 不信可以试下下面的数据
000159 000519 ans:8 700638 815339 ans:14
感想:开始拿到这道题目 天真的用朴素的单搜做了 华丽丽的TLE 只能怪自己没有预估状态 这题直接处理状态数太多 有6*1000000种 显然不管是单搜还是双搜都是处理不了的
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <map> using namespace std; int ans,cnt; int tpos,tstep,tst; int s1[6],s2[6],s22[6],st[6]; char in1[10],in2[10]; int start[10],end[10]; int vis[6][6][6][6][6][6][6][10]; // 判重数组 0~5-各位置所对应的值 6~光标所在位置 7~光标访问状态 int mouse[10][6]= // 光标的10种访问情况 { 1,0,0,0,0,0, 1,1,0,0,0,0, 1,1,1,0,0,0, 1,1,1,1,0,0, 1,1,1,1,1,0, 1,1,1,1,1,1, 1,0,0,0,0,1, 1,1,0,0,0,1, 1,1,1,0,0,1, 1,1,1,1,0,1 }; struct Node { int s[6]; int pos,step,state; } cur,now; int value[44000][8]; // 0~5 对应的s的值 6~state 7~step 将各种状态记录下来 queue<Node>q; int getstate() // 获取光标访问状态 { int i,j,flag; for(i=0;i<10;i++) { flag=1; for(j=0;j<6;j++) { if(mouse[i][j]!=st[j]) flag=0; } if(flag) return i; } } void bfs() { int i,j,temp; while(!q.empty()) q.pop(); memset(vis,0,sizeof(vis)); cnt=0; for(i=0;i<6;i++) { cur.s[i]=i; } cur.pos=0; cur.step=0; cur.state=0; q.push(cur); vis[0][1][2][3][4][5][0][0]=1; while(!q.empty()) { now=q.front(); tstep=now.step; tpos=now.pos; tst=now.state; memcpy(s1,mouse[tst],sizeof(s1)); memcpy(s2,now.s,sizeof(s2)); cnt++; for(i=0;i<6;i++) { value[cnt][i]=s2[i]; } value[cnt][6]=tst; value[cnt][7]=tstep; if(tpos!=0) // 左移 { cur.pos=tpos-1; memcpy(st,s1,sizeof(s1)); st[tpos-1]=1; cur.state=getstate(); if(!vis[s2[0]][s2[1]][s2[2]][s2[3]][s2[4]][s2[5]][tpos-1][cur.state]) { vis[s2[0]][s2[1]][s2[2]][s2[3]][s2[4]][s2[5]][tpos-1][cur.state]=1; memcpy(cur.s,s2,sizeof(s2)); cur.step=tstep+1; q.push(cur); } } if(tpos!=5) // 右移 { cur.pos=tpos+1; memcpy(st,s1,sizeof(s1)); st[tpos+1]=1; cur.state=getstate(); if(!vis[s2[0]][s2[1]][s2[2]][s2[3]][s2[4]][s2[5]][tpos+1][cur.state]) { vis[s2[0]][s2[1]][s2[2]][s2[3]][s2[4]][s2[5]][tpos+1][cur.state]=1; memcpy(cur.s,s2,sizeof(s2)); cur.step=tstep+1; q.push(cur); } } if(tpos!=0) // 与0号位置交换 { memcpy(st,s1,sizeof(s1)); memcpy(s22,s2,sizeof(s2)); temp=s22[tpos]; s22[tpos]=s22[0]; s22[0]=temp; st[0]=1; cur.state=getstate(); if(!vis[s22[0]][s22[1]][s22[2]][s22[3]][s22[4]][s22[5]][tpos][cur.state]) { vis[s22[0]][s22[1]][s22[2]][s22[3]][s22[4]][s22[5]][tpos][cur.state]=1; cur.step=tstep+1; cur.pos=tpos; memcpy(cur.s,s22,sizeof(s22)); q.push(cur); } } if(tpos!=5) // 与5号位置交换 { memcpy(st,s1,sizeof(s1)); memcpy(s22,s2,sizeof(s2)); temp=s22[tpos]; s22[tpos]=s22[5]; s22[5]=temp; st[5]=1; cur.state=getstate(); if(!vis[s22[0]][s22[1]][s22[2]][s22[3]][s22[4]][s22[5]][tpos][cur.state]) { vis[s22[0]][s22[1]][s22[2]][s22[3]][s22[4]][s22[5]][tpos][cur.state]=1; cur.step=tstep+1; cur.pos=tpos; memcpy(cur.s,s22,sizeof(s22)); q.push(cur); } } q.pop(); } } int main() { int i,j,sum,fflag; bfs(); // 一次bfs就ok了 能够存下6!前四种操作后的每个数字对应的位置及光标访问状态 while(~scanf("%s%s",in1,in2)) { for(i=0;i<6;i++) { start[i]=in1[i]-'0'; end[i]=in2[i]-'0'; } ans=100000000; for(i=1;i<=cnt;i++) // 每次枚举所有情况更新ans { sum=0; fflag=1; for(j=0;j<6;j++) { if(mouse[value[i][6]][j]) // 只有被光标访问了的位置才能改变大小 { sum+=fabs(end[j]-start[value[i][j]]); } else { if(end[j]!=start[value[i][j]]) fflag=0; // 如果没访问 且值不与最终状态相同 肯定不行 } } if(fflag) { if(ans>sum+value[i][7]) ans=sum+value[i][7]; } } printf("%d\n",ans); } } /* 000159 000519 ans:8 700638 815339 ans:14 */