POJ1184-------操作分离的BFS
题目地址:http://poj.org/problem?id=1184
题目意思:
给你两个6位数,一个是起始值,一个最终值
初始光标在最左边
你可以左移或者右移光变
在光标处+1或者-1
在光标处和最左边或者和最右边交换
问你最少要多少就可以由初始值转换到最终值
解题思路:
操作分离是解决这题的核心思想
就是说我们反正要进行一些转换的,不如先全部转换了算了
通过一个BFS预处理将所有可能转换的全部转换,光标所有可能的位置全部求出来
然后在每次要求的时候,对每种状态上的光标进行加减操作
求出最少的步骤
另外这题的测试数据有问题,其实左移也是需要的
比如000159 和 000519,正确答案是8,如果不考虑左移就是12
再就是我们可以将光标的访问情况压缩到10种,具体的在我代码中有解释
下面上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<string> #include<map> #include<queue> using namespace std; struct node { int state; int pos; int num[6]; int step; int fangwen[6]; }; int vis_state[10][6] = { 1,0,0,0,0,0, /*访问状态0: 初始状态(pos=0)*/ 1,1,0,0,0,0, /*访问状态1: 状态0通过右移操作得到(pos=1),或者状态1通过swap0操作得到(pos=1)*/ 1,1,1,0,0,0, /*访问状态2: 状态1通过右移操作得到(pos=2),或者状态2通过swap0操作得到(pos=2)*/ 1,1,1,1,0,0, /*访问状态3: 状态2通过右移操作得到(pos=3),或者状态3通过swap0操作得到(pos=3)*/ 1,1,1,1,1,0, /*访问状态4: 状态3通过右移操作得到(pos=4),或者状态4通过swap0操作得到(pos=4)*/ 1,0,0,0,0,1, /*访问状态5: 状态0通过swap1操作得到(pos=0),或者状态5通过swap0操作得到(pos=0)*/ 1,1,0,0,0,1, /*访问状态6: 状态1通过swap1操作得到(pos=1),或者状态5通过右移操作得到(pos=1),或者状态6通过swap0操作得到(pos=1)*/ 1,1,1,0,0,1, /*访问状态7: 状态2通过swap1操作得到(pos=2),或者状态6通过右移操作得到(pos=2),或者状态7通过swap0操作得到(pos=2)*/ 1,1,1,1,0,1, /*访问状态8: 状态3通过swap1操作得到(pos=3),或者状态7通过右移操作得到(pos=3),或者状态8通过swap0操作得到(pos=3)*/ 1,1,1,1,1,1 /*访问状态9: 状态4通过swap1操作得到(pos=4),或者状态8通过右移操作得到(pos=4),或者状态9通过右移操作得到(pos=5), 或者状态4通过右移操作得到(pos=5),或者状态9通过swap0操作得到,或者状态9通过swap1操作得到*/ }; int state[10000][8]; //对应的是所有情况,第二维记录相应信息 int idx; int co; bool vis[6][6][6][6][6][6][6][10]; //前6个是数字,为什么只到6,是因为这个是做排列用的 //第7个是光标所在位置用的,第8个事state void put_to_vis(node a) { vis[a.num[0]][a.num[1]][a.num[2]][a.num[3]][a.num[4]][a.num[5]][a.pos][a.state] = true; } bool check(node a) { return vis[a.num[0]][a.num[1]][a.num[2]][a.num[3]][a.num[4]][a.num[5]][a.pos][a.state]; } int find_state(node a) { if(a.fangwen[5]==0) { int cnt = 0; for(int i=1;i<5;i++) if(a.fangwen[i]) cnt++; return cnt; } else { int cnt = 0; for(int i=1;i<5;i++) if(a.fangwen[i]) cnt++; return cnt+5; } } void bfs() { queue<node> Q; node a,b; idx=0; co=0; for(int i=0;i<6;i++) { a.num[i] = i; a.fangwen[i] = 0; } a.pos = a.state = a.step = 0; a.fangwen[0] = 1; Q.push(a); put_to_vis(a); //printf("a step %d\n",a.step); int co2=0; while(!Q.empty()) { co++; a = Q.front(); Q.pop(); for(int i=0;i<6;i++) state[idx][i] = a.num[i]; state[idx][6] = a.state; state[idx][7] = a.step; idx++; if(a.pos>0) //左移或者左交换操作 { //左移操作 b=a; b.step = a.step+1; b.pos--; if(!check(b)) { put_to_vis(b); Q.push(b); } //左交换 b = a; b.step = a.step+1; swap(b.num[0],b.num[b.pos]); if(!check(b)) { put_to_vis(b); Q.push(b); } } if(a.pos<5) //右移和右交换操作 { //右移 b=a; b.step = a.step+1; b.pos++; b.fangwen[b.pos] = 1; b.state = find_state(b); if(!check(b)) { put_to_vis(b); Q.push(b); } //右交换 b = a ; b.step = a.step+1; swap(b.num[5],b.num[b.pos]); b.fangwen[5] = 1; b.state = find_state(b); if(!check(b)) { put_to_vis(b); Q.push(b); } } } } int main() { memset(vis,false,sizeof(vis)); bfs(); char st[10]; char ed[10]; int _st[6]; int _ed[6]; while(scanf("%s%s",st,ed) != EOF) { for(int i=0;i<6;i++) { _st[i] = st[i]-'0'; _ed[i] = ed[i]-'0'; } int ans = 99999999; for(int i=0;i<idx;i++) { int tmp = state[i][7];//初始化为进行了交换后的步数 bool flag = true; int j; for(j=0;j<6;j++) { if(!vis_state[state[i][6]][j] && (_st[state[i][j]]!=_ed[j]) ) { flag = false; break; } else { tmp += abs( _st[state[i][j]] - _ed[j]); //再加上每位进行加减 操作的步数 } } if(flag) ans = min(ans,tmp); } printf("%d\n",ans); } return 0; }