您的位置:首页 > 其它

HDU-3567 Eight II

2018-03-09 23:32 155 查看
八数码问题,给出初始状态和结束状态,要输出最短移动路径中字典序最小的那个,输入保证有解因为数据量比较多,不能单纯的BFS,双向BFS也不能保证字典序,这里利用了映射的思想以及打表

先以X12345678,1X2345678.....,1234567X8,12345678X为开始进行BFS,把路径分开保存好然后将起始状态映射为以上其中的一个(X的位置一样的那个),相应的把结束状态转变过去,再寻找路径回去即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int N=362880+10;
const int dm[]={3,-1,1,-3};
const char mop[]={'d','l','r','u'}; //这里的移动是与dm对应的
const int ten[]={1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1};
bool vis[9]
; //访问标记
int f[9]
; //保存父节点
char op[9]
; //保存移动
int move(int n,int i) //移动
{
int pos=9,tmp=n;
while(pos>1)
{
if(n%10==0) break;
n/=10;
pos--;
}
if(pos%3==1&&i==1) return -1;
if(pos%3==0&&i==2) return -1;
if(pos<4&&i==3) return -1;
if(pos>6&&i==0) return -1;
int np=pos+dm[i];
int t=tmp%ten[np-1]/ten[np];
tmp+=ten[pos]*t;
tmp-=ten[np]*t;
return tmp;
}
int fact[9]; //编码用
void init() //初始化
{
fact[0]=1;
for(int i=1;i<9;i++)
fact[i]=fact[i-1]*i;
memset(vis,false,sizeof(vis));
memset(f,-1,sizeof(f));
}
int get_code(int s) //康托展开
{
int code=0;
int st[9];
for(int i=8;i>=0;i--,s/=10)
st[i]=s%10;
for(int i=0;i<9;i++)
{
int cnt=0;
for(int j=i+1;j<9;j++)
if(st[j]<st[i]) cnt++;
code+=fact[8-i]*cnt;
}
return code;
}
bool insert(int code,int k) //检查是否访问过
{
if(vis[k][code]) return false;
return vis[k][code]=true;
}
void bfs(int sta0,int k)
{
queue<int> q;
q.push(sta0);
insert(get_code(sta0),k);
while(!q.empty()) //BFS,打表
{
int u=q.front();
q.pop();
int codu=get_code(u);
for(int i=0;i<4;i++)
{
int v=move(u,i);
if(v==-1) continue;
int code=get_code(v);
if(insert(code,k))
{
q.push(v);
f[k][code]=codu; //记录父节点
op[k][code]=mop[i]; //记录到父节点的操作
}
}
}
}
char a[10],b[10];
int m[9]; //映射用数组
int main()
{
init();
int sta0=12345678,sta; //全部入队
bfs(sta0,0);
sta0=102345678;
bfs(sta0,1);
sta0=120345678;
bfs(sta0,2);
sta0=123045678;
bfs(sta0,3);
sta0=123405678;
bfs(sta0,4);
sta0=123450678;
bfs(sta0,5);
sta0=123456078;
bfs(sta0,6);
sta0=123456708;
bfs(sta0,7);
sta0=123456780;
bfs(sta0,8);
int T,kase=0;
scanf("%d",&T);
while(T--)
{
sta=sta0=0;
int t=1,k;
m[0]=0;
scanf("%s",a);
for(int i=0;i<9;i++)
if(a[i]!='X') m[a[i]-'0']=t++; //映射
else k=i;
scanf("%s",b);
for(int i=0;i<9;i++)
{
sta*=10;
if(b[i]!='X') sta+=m[b[i]-'0']; //转化后的状态
}
int code=get_code(sta),cnt=0;;
stack<char> s;
while(f[k][code]!=-1) //寻找父节点,将移动操作入栈
{
s.push(op[k][code]);
code=f[k][code];
cnt++;
}
printf("Case %d: %d\n",++kase,cnt); //输出
while(!s.empty())
{
printf("%c",s.top());
s.pop();
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: