Information
- ID
- 29
- Time
- 1000ms
- Memory
- 512MiB
- Difficulty
- 8
- Tags
- # Submissions
- 18
- Accepted
- 6
- Uploaded By
难度: 绿
算法: 最短路,广度优先搜索
说句实话,这题真的是太【数据删除】了。输出最小操作次数就算了,还让我们输出操作序列,还要输出字典序最小的,致使我调了 4 小时。赛前练最短路结果拿这种题恶心我,一本通我谢谢你。
一眼最短路。
观察到这题有一个不错的性质:魔板至多有 8!=40320 种状态,于是每种状态建一个点,每种操作连一条有向边,跑最短路即可。你可能需要多加一个关键字表示操作序列。
鉴于本题代码量极大,在此放上代码,调不过去的同学可以参考。
#include<bits/stdc++.h>
using namespace std;
int n,k[8],cnt=0,c,u,v,w,tp,dis[41000],vis[41000];
string s,sv[41000];
map<string,int> m;
struct node{
int u,dis,ty;
string ans;
bool operator > (const node& a) const {return dis!=a.dis?dis>a.dis:ans<a.ans;}
}h;
vector<node> e[130000];
priority_queue<node,vector<node>,greater<node> > q;
string opa(string a){
string re="";
re=re+a[7]+a[6]+a[5]+a[4]+a[3]+a[2]+a[1]+a[0];
return re;
}
string opb(string a){
string re="";
re=re+a[3]+a[0]+a[1]+a[2]+a[5]+a[6]+a[7]+a[4];
return re;
}
string opc(string a){
string re="";
re=re+a[0]+a[6]+a[1]+a[3]+a[4]+a[2]+a[5]+a[7];
return re;
}
void build(int le,int ri,int te){
h.u=ri,h.ans=char(te+'A');
e[le].push_back(h);
return ;
}
int main(){
memset(dis,0x3f3f3f,sizeof(dis));
h.dis=1;
for(int i=0;i<8;i++) k[i]=i+1;
do{
s="";
for(int i=0;i<8;i++) s=s+char(k[i]+'0');
m[s]=++cnt;
}while(next_permutation(k,k+8));
for(int i=0;i<8;i++) k[i]=i+1;
do{
s="";
for(int i=0;i<8;i++) s=s+char(k[i]+'0');
build(m[s],m[opa(s)],0);
build(m[s],m[opb(s)],1);
build(m[s],m[opc(s)],2);
}while(next_permutation(k,k+8));
s="";
for(int i=0;i<8;i++) scanf("%d",&k[i]),s=s+char(k[i]+'0');
c=m[s];
dis[1]=0;
h.u=1,h.dis=0,h.ans="";
q.push(h);
while(!q.empty()){
u=q.top().u;
q.pop();
if(vis[u]==1) continue;
vis[u]=1;
for(int i=0;i<int(e[u].size());i++){
s=sv[u];
v=e[u][i].u,w=e[u][i].dis,s=s+e[u][i].ans;
if(dis[v]>dis[u]+w||(dis[v]==dis[u]+w&&sv[v]>s)){
dis[v]=dis[u]+w,sv[v]=s;
h.u=v,h.dis=dis[v],h.ans=s;
q.push(h);
}
}
}
printf("%d\n",dis[c]);
cout<<sv[c];
return 0;
}
By signing up a HFOJ universal account, you can submit code and join discussions in all online judging services provided by us.