宽搜 + 康托展开
两题其实是一样的两道题,可以训练宽搜,但是,这两题作为宽搜其实是水题,比较难的地方其实是对状态的记录,即队列的元素采用什么来保存,这里用到了康托展开(介绍点这儿)
解决了保存的问题,接下来的都是琐事了,上代码:
//sicily 1150 简单魔板
#include <bits/stdc++.h>
using namespace std;
int n,m,goal,tmp[10],v[10];
int factor[]={1,1,2,6,24,120,720,5040,40320,362880};
struct node{
int val;
string str;
node(int val=0,string st=""):val(val),str(st){}
};
int cantor(){
int sum=0;
for(int i=0;i<n;i++)
{
int cnt=0;
for(int j=i+1;j<n;j++)
if(tmp[j]<tmp[i])
cnt++;
sum+=cnt*factor[n-i-1];
}
return sum+1;
}
void inv_cantor(int num)
{
num--;
memset(v,0,sizeof(v));
for(int i=0;i<n;i++)
{
int index=num/factor[n-i-1],j=1;
for(j=1;j<=n;j++)
if(!v[j])
{
if(!index)
break;
index--;
}
tmp[i]=j,v[j]=1;
num%=factor[n-i-1];
}
}
void print()
{
for(int i=0;i<8;i++)
cout<<tmp[i];
cout<<endl;
}
int A(int num)
{
inv_cantor(num);
for(int i=0;i<4;i++)
swap(tmp[i],tmp[i+4]);
return cantor();
}
int B(int num)
{
inv_cantor(num);
tmp[8]=tmp[3],tmp[9]=tmp[7];
for(int i=2;i>=0;i--)
tmp[i+1]=tmp[i];
for(int i=6;i>=4;i--)
tmp[i+1]=tmp[i];
tmp[0]=tmp[8],tmp[4]=tmp[9];
return cantor();
}
int C(int num)
{
inv_cantor(num);
tmp[8]=tmp[1];
tmp[1]=tmp[5],tmp[5]=tmp[6],tmp[6]=tmp[2];
tmp[2]=tmp[8];
return cantor();
}
int main()
{
n=8;
string a="A",b="B",c="C";
while(cin>>m&&m>=0)
{
for(int i=0;i<n;i++)
cin>>tmp[i];
goal=cantor();
queue<node> q;
q.push(node(24,""));
node front;
while(!q.empty())
{
front=q.front();
q.pop();
if(front.val==goal)
break;
if(front.str.size()>10)
{
front=node(-1,"");
break;
}
q.push(node(A(front.val),front.str+a));
q.push(node(B(front.val),front.str+b));
q.push(node(C(front.val),front.str+c));
}
if(front.val==-1)
cout<<-1<<endl;
else
cout<<front.str.size()<<" "<<front.str<<endl;
}
return 0;
}
加个剪枝就变成了第二题的代码:
//sicily 1151 魔板
#include <bits/stdc++.h>
using namespace std;
int n,m,goal,tmp[10],v[10],vis[45005];
int factor[]={1,1,2,6,24,120,720,5040,40320,362880};
struct node{
int val;
string str;
node(int val=0,string st=""):val(val),str(st){}
};
int cantor(){
int sum=0;
for(int i=0;i<n;i++)
{
int cnt=0;
for(int j=i+1;j<n;j++)
if(tmp[j]<tmp[i])
cnt++;
sum+=cnt*factor[n-i-1];
}
return sum+1;
}
void inv_cantor(int num)
{
num--;
memset(v,0,sizeof(v));
for(int i=0;i<n;i++)
{
int index=num/factor[n-i-1],j=1;
for(j=1;j<=n;j++)
if(!v[j])
{
if(!index)
break;
index--;
}
tmp[i]=j,v[j]=1;
num%=factor[n-i-1];
}
}
void print()
{
for(int i=0;i<8;i++)
cout<<tmp[i];
cout<<endl;
}
int A(int num)
{
inv_cantor(num);
for(int i=0;i<4;i++)
swap(tmp[i],tmp[i+4]);
return cantor();
}
int B(int num)
{
inv_cantor(num);
tmp[8]=tmp[3],tmp[9]=tmp[7];
for(int i=2;i>=0;i--)
tmp[i+1]=tmp[i];
for(int i=6;i>=4;i--)
tmp[i+1]=tmp[i];
tmp[0]=tmp[8],tmp[4]=tmp[9];
return cantor();
}
int C(int num)
{
inv_cantor(num);
tmp[8]=tmp[1];
tmp[1]=tmp[5],tmp[5]=tmp[6],tmp[6]=tmp[2];
tmp[2]=tmp[8];
return cantor();
}
int main()
{
n=8;
string a="A",b="B",c="C";
while(cin>>m&&m>=0)
{
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
cin>>tmp[i];
goal=cantor();
queue<node> q;
q.push(node(24,""));
node front;
v[24]=1;
while(!q.empty())
{
front=q.front();
q.pop();
if(front.val==goal)
break;
if(front.str.size()>m)
{
front=node(-1,"");
break;
}
if(!vis[A(front.val)]) q.push(node(A(front.val),front.str+a));
if(!vis[B(front.val)]) q.push(node(B(front.val),front.str+b));
if(!vis[C(front.val)]) q.push(node(C(front.val),front.str+c));
vis[A(front.val)]=1;
vis[B(front.val)]=1;
vis[C(front.val)]=1;
}
if(front.val==-1)
cout<<-1<<endl;
else
cout<<front.str.size()<<" "<<front.str<<endl;
}
return 0;
}