poj 1184 广搜 状态压缩
题意:6个数字,每次可以左移/右移光标,或将光标所在数字加一/减一,或将光标所在数字与第一个/第六个数字交换,问达到目标数字,最少需要多少次操作?
分析:操作可以分成两部分考虑:移动光标和交换改变了原数字的位置,而加一减一改变数字的大小。
先bfs出012345所能达到的所有状态,以及达到此状态光标经过了哪些数字。再针对新状态和目标状态,如果某一位数字不一样并且光标经过这一位,则可以改变此数字的大小,若没经过,则此状态无法达到目标状态。表达起来太费劲了,直接看代码吧。
另外,据说左移操作是多余的,把代码中左移部分去掉,也AC了,但还是感觉有问题。。 有空再想吧。。
const int M = 567; struct node{ int a[6], step, pos, sta;//数字的排列 步数 光标位置 光标经过的状态 }d[M]; int h, r;//队列首尾指针 bool sta[10][6] = { {1,0,0,0,0,0}, //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,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}, }; bool b[6][6][6][6][6][6][6][10];//判重 #define vis b[d[h].a[0]][d[h].a[1]][d[h].a[2]][d[h].a[3]][d[h].a[4]][d[h].a[5]][d[h].pos][d[h].sta] void bfs(){ FOR(i, 0, 6) d[h].a[i] = i; d[h].step = 0; d[h].pos = 0; d[h].sta = 0; vis = 1; h++; while(r<h){ if(d[r].pos<5){ //光标右移 d[h].step=d[r].step+1; d[h].pos=d[r].pos+1; if(sta[d[r].sta][d[r].pos+1]) d[h].sta=d[r].sta; else if(d[r].sta==9) d[h].sta=5; else d[h].sta=d[r].sta+1; FOR(i, 0, 6) d[h].a[i]=d[r].a[i]; if(vis==0) { vis=1; h++;} //和6交换 d[h].step=d[r].step+1; d[h].pos=d[r].pos; if(d[r].sta<4) d[h].sta=d[r].sta+6; else if(d[r].sta==4) d[h].sta=5; else d[h].sta=d[r].sta; FOR(i, 0, 6) d[h].a[i]=d[r].a[i]; swap(d[h].a[d[h].pos], d[h].a[5]); if(vis==0) { vis=1; h++;} } if(d[r].pos>0){ //光标左移 /*d[h].step=d[r].step+1; d[h].pos=d[r].pos-1; d[h].sta=d[r].sta; FOR(i, 0, 6) d[h].a[i]=d[r].a[i]; if(vis==0) { vis=1; h++;} */ //和1交换 d[h].step=d[r].step+1; d[h].pos=d[r].pos; d[h].sta=d[r].sta; FOR(i, 0, 6) d[h].a[i]=d[r].a[i]; swap(d[h].a[d[h].pos], d[h].a[0]); if(vis==0) { vis=1; h++;} } r++; } } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif bfs(); string s1,s2; cin>>s1>>s2; int x[6], y[6]; FOR(i, 0, 6) x[i]=s1[i]-'0', y[i]=s2[i]-'0'; int ans=-1; FOR(p, 0, h){ //cout<<h<<endl; int flag=0, cnt=d[p].step, s=d[p].sta; FOR(i, 0, 6) if( x[ d[p].a[i] ] != y[i] ) { if( sta[s][i] == 0 ) {flag=1; break;} else cnt += abs( x[ d[p].a[i] ]-y[i] ); } if(flag) continue; checkmin(ans, cnt); } cout<<ans<<endl; return 0; }