搜索—跳蚱蜢

题目描述

如图所示: 有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;
}
posted @ 2023-08-21 01:48  LongDz  阅读(38)  评论(0)    收藏  举报