Digit Dancing
题意:
给你8个数,他们的绝对值组成一个1~8的一个排列,每次操作允许找到同时满足下列情况的两个数
ai,aj
,把
ai放到aj的任一侧
,或者把
aj放到ai的任一侧
:
- ai,aj 两个数一正一负
- abs(ai)+abs(aj) 是素数
问最少操作几次让这8个数按绝对值递增排列。
题解:
8!很小,按题意爆搜即可。
#include<bits/stdc++.h>
using namespace std;
struct node{
int a[10], t;
node(){ t = 0; for(int i = 1; i < 10; ++i) a[i] = 0; }
void scan(){ for(int i = 1; i <= 8; ++i) scanf("%d", a+i); t = 0; }
int hash(){
int res = 0;
for(int i = 1; i <= 8; ++i) res = res*10+abs(a[i]);
return res;
}
node movel(int i, int pos){
node res = *this;
if(i < pos){
while(res.a[i+1] != a[pos]) swap(res.a[i+1], res.a[i]), ++i;
}
else{
while(res.a[i+1] != a[pos]) swap(res.a[i-1], res.a[i]), --i;
}
return res;
}
node mover(int i, int pos){
node res = *this;
if(i < pos){
while(res.a[i-1] != a[pos]) swap(res.a[i+1], res.a[i]), ++i;
}
else{
while(res.a[i-1] != a[pos]) swap(res.a[i-1], res.a[i]), --i;
}
return res;
}
bool solved(){
for(int i = 1; i <= 8; ++i){
if(a[i] != i && a[i] != -i) return 0;
}
return 1;
}
}s;
int prime[50] = {0};
void init(){
prime[2] = prime[3] = 1;
for(int i = 5; i < 50; i += 2){
for(int j = 2; j < i; ++j){
if(i%j == 0) break;
if(j == i-1) prime[i] = 1;
}
}
}
int bfs(node s){
queue<node>q;
set<int>st;
q.push(s); st.insert(s.hash());
while(!q.empty()){
node now = q.front(); q.pop();
if(now.solved()) return now.t;
now.t++;
for(int i = 1; i <= 8; ++i){
if(now.a[i] > 0) continue; // <0
for(int j = 1; j <= 8; ++j){
if(now.a[j] < 0) continue; // >0
if(!prime[-now.a[i]+now.a[j]]) continue;
node nex = now.movel(i, j);
if(st.count(nex.hash()) == 0){
q.push(nex);
st.insert(nex.hash());
}
nex = now.mover(i, j);
if(st.count(nex.hash()) == 0){
q.push(nex);
st.insert(nex.hash());
}
nex = now.movel(j, i);
if(st.count(nex.hash()) == 0){
q.push(nex);
st.insert(nex.hash());
}
nex = now.mover(j, i);
if(st.count(nex.hash()) == 0){
q.push(nex);
st.insert(nex.hash());
}
}
}
}
return -1;
}
int main(){
init();
int T, ca = 1;
scanf("%d", &T);
while(T--){
s.scan();
printf("Case %d: %d\n", ca++, bfs(s));
}
}