Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5839 | Accepted: 1190 |
Description
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 */