搜索—跳蚱蜢
题目描述
如图所示: 有9只盘子,排成1个圆圈。其中8只盘子内装着8只蚱蜢,有一个是空盘。

我们把这些蚱蜢顺时针编号为 1~8。每只蚱蜢都可以跳到相邻的空盘中,也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。
请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,并且保持空盘的位置不变(也就是1-8换位,2-7换位,...),至少要经过多少次跳跃
分析
这道题属于八数码问题,我们把空盘编号为0,为了方便做题与思考,使用两个小技巧:研究蚱蜢跳转为研究空盘跳;化圆为线。题目概括:从初始状态:012345678 变为 087654321 需要操作多少次。我们发现从初始状态跳有4种情况,如图:
用判重来减少搜索次数
#include<bits/stdc++.h>
using namespace std;
const int LEN = 362880;
int visited [LEN] = {0};
long int factory[] = {1,1,2,6,24,120,720,5040,40320,362880};
struct node{
node(){}
node(string ss, int tt){s = ss, t = tt;}
string s;
int t;
};
bool Cantor(string str,int n){
long result = 0;
for(int i = 0;i < n;i++){
int counted = 0;
for(int j = i+1;j < n;j++){
if(str[i]>str[j])
++counted;
}
result += counted * factory[n-i-1];
}
if(!visited[result]){
visited[result] = 1;
return 1;
}
else
return 0;
}
queue<node> q;
void solve(){
while(!q.empty()){
node now = q.front();
q.pop();
string s = now.s;
int step = now.t;
if(s == "087654321"){ cout<<step<<endl; break;} //到目标了,输出跳跃步数
int i;
for(i = 0 ; i < 10 ; i++) //找到盘子的位置i
if(s[i] == '0') break;
for(int j = i - 2 ; j <= i + 2 ; j++){ //4种跳法
int k = (j + 9) % 9;
if(k == i) continue; //这是当前状态,不用检查
string news = s;
char tmp = news[i];
news[i] = news[k];
news[k] = tmp; //跳到一种情况
if(Cantor(news,9)){ //判重:这个情况没有出现过
q.push(node(news, step + 1));
}
}
}
}
int main(){
//clock_t start = clock();
string s = "012345678";
q.push(node(s, 0));
Cantor(s,9);
solve();
//clock_t end = clock();
//double t = double(end-start) / CLOCKS_PER_SEC;
//cout<<'\n'<<t<<endl;
return 0;
}
Cantor函数使用康托判重,博客有记录。
可以使用set或map进行判重比较好写
#include<bits/stdc++.h>
using namespace std;
struct node{
node(){}
node(string ss, int tt){s = ss, t = tt;}
string s;
int t;
};
//(1) map
map<string, bool> mp;
//(2) set
// set<string> visited; //记录已经搜索过的状态
queue<node> q;
void solve(){
while(!q.empty()){
node now = q.front();
q.pop();
string s = now.s;
int step = now.t;
if(s == "087654321"){ cout<<step<<endl; break;} //到目标了,输出跳跃步数
int i;
for(i = 0 ; i < 10 ; i++) //找到盘子的位置i
if(s[i] == '0') break;
for(int j = i - 2 ; j <= i + 2 ; j++){ //4种跳法
int k = (j + 9) % 9;
if(k == i) continue; //这是当前状态,不用检查
string news = s;
char tmp = news[i];
news[i] = news[k];
news[k] = tmp; //跳到一种情况
//(1) map
if(!mp[news]){ //判重:这个情况没有出现过
mp[news] = true;
q.push(node(news, step + 1));
}
//(2)set
/* if(visited.count(news)==0){ //判重:这个情况没有出现过
visited.insert(news);
q.push(node(news, step + 1));
} */
}
}
}
int main(){
string s = "012345678";
q.push(node(s, 0));
//(1) map
mp[s] = true;
solve();
return 0;
}

浙公网安备 33010602011771号