2158-Double Sorting
問題概要
数字二つのペアがn個ある.隣り合ったペアの2つの数値を交換することが出来るとき,ペアがソートされた状態になるのは最小何回の交換が必要か.
解法
最良優先探索+嘘枝刈り.
各数値の正しい位置との距離が近い順に探索する.
さらに,後ろからBFSをある程度して計算する量を大幅に減らすようにする.
がこれだけでは通らず,さらに謎な定数調整が必要になってしまった.
実装(C++)
#include <cstdio> #include <queue> #include <algorithm> #include <iostream> #include <string> #include <tr1/unordered_map> using namespace std; typedef unsigned long long ull; #define REP(i,x) for(int i=0;i<(int)(x);i++) int n; int p[2][8]; ull pow_eight[16]={ 1ULL, 8ULL, 64ULL, 512ULL, 4096ULL, 32768ULL, 262144ULL, 2097152ULL, 16777216ULL, 134217728ULL, 1073741824ULL, 8589934592ULL, 68719476736ULL, 549755813888ULL, 4398046511104ULL, 35184372088832ULL}; ull mul[16][8]; int res[8]={0,2,5,10,15,23,31,40}; struct State{ ull hash; int value[8][2]; int dist; void init(){ hash=0; REP(i,n){ REP(j,2){ value[i][j]=p[j][i]; dist+=abs(i-value[i][j]); } if(value[i][0]>value[i][1])swap(value[i][0],value[i][1]); } REP(i,n)REP(j,2)hash+=mul[i*2+j][value[i][j]]; } void swap_value(int k,int a,int b){ REP(i,2){ REP(j,2){ dist-=abs(i+k-value[i+k][j]); hash-=mul[(i+k)*2+j][value[i+k][j]]; } } swap(value[k][a],value[k+1][b]); REP(i,2){ if(value[i+k][0]>value[i+k][1]){ swap(value[i+k][0],value[i+k][1]); } } REP(i,2){ REP(j,2){ dist+=abs(i+k-value[i+k][j]); hash+=mul[(i+k)*2+j][value[i+k][j]]; } } } State(){ hash=0; dist=0; } }; bool operator<(const State &a,const State &b){ return a.dist>b.dist; } tr1::unordered_map<ull,int> bfs[9]; tr1::unordered_map<ull,int> ac; int solve(){ priority_queue<State> que; State s; ac.clear(); s.init(); que.push(s); ac[s.hash]=0; int ans=34; while(!que.empty()){ State tmp=que.top();que.pop(); int now=ac[tmp.hash]; int nn=tmp.dist; if(now>=ans)continue; if((tmp.dist+1)/2+now>=ans)continue; if(bfs[n].find(tmp.hash)!=bfs[n].end()){ ans=min(ans,now+bfs[n][tmp.hash]); continue; } State next; for(int i=0;i<n-1;i++){ REP(a,2)REP(b,2){ next=tmp; next.swap_value(i,a,b); if(next.dist<=nn){ if(ac.find(next.hash)==ac.end()||ac[next.hash]>now+1){ ac[next.hash]=now+1; que.push(next); } } } } } cout<<ans<<endl; return 0; } void BFS(){ queue<State> que; State s; ac.clear(); s.init(); que.push(s); ac[s.hash]=0; while(!que.empty()){ State tmp=que.front();que.pop(); int now=ac[tmp.hash]; bfs[n][tmp.hash]=now; if(now>=5)return; State next; for(int i=0;i<n-1;i++){ REP(a,2)REP(b,2){ next=tmp; next.swap_value(i,a,b); if(ac.find(next.hash)==ac.end()){ ac[next.hash]=now+1; que.push(next); } } } } } int main(){ REP(i,8)REP(j,16)mul[j][i]=i*pow_eight[j]; for(n=1;n<=8;n++){ REP(i,n)REP(j,2){ p[j][i]=i; } BFS(); } while(cin>>n,n){ REP(i,n){ REP(j,2){ cin>>p[j][i]; p[j][i]--; } } bool ps=true; REP(i,n){ if(!(p[0][i]==n-i-1&&p[1][i]==n-i-1)){ ps=false;break; } } if(ps){ cout<<res[n-1]<<endl;continue; } solve(); } return 0; }