Judgment in search (take BFS as an example)

Forecast: The new book " Algorithm Competition ", which I wrote in two years , has been handed over to Tsinghua University Press in February 2022 and is expected to be published in July 2022. "Algorithm Competition" is a " Compendium ", covering "Basic-Intermediate-Advanced", with a length of about 700 pages. Drafts of some knowledge points have been published on this blog. This blog is an excerpt from "3.2.1 BFS Judgment" of the new book "Algorithm Competition".


   Judge weight, that is, judge whether the current state has been processed before. If it has been processed, there is no need to process it again. From this perspective, weight judgment is a pruning technique.
   Judgment weight is often used in BFS, and many problems of BFS pruning need weight judgment.
   The principle of BFS is to gradually expand the next layer, and put the expanded next layer points into the queue for processing. While processing the previous layer, put the points of the next layer at the end of the queue. At any moment, the queue only contains points of two adjacent layers. If these points are all different, you can only put all points into the queue. If these points are the same, it is enough to process the same point only once, and other identical points do not need to be processed repeatedly, and weight judgment is required at this time.
   The following real question is the BFS weight judgment.


2017 Lanqiao Cup Provincial Competition Real Question
Jumping Grasshopper https://www.lanqiao.cn/problems/642/learning/
Title description: There are 9 plates arranged in a circle. Eight of the plates contained eight grasshoppers, and one was empty.
Number these grasshoppers clockwise from 1 to 8. Each grasshopper can jump to an adjacent empty disk, or with a little more force, jump over an adjacent grasshopper and jump to an empty disk.
Please calculate, if you want to change the formation of the grasshoppers to counterclockwise and keep the position of the empty plate unchanged (that is, 1-8 transposition, 2-7 transposition, ...), at least how many jumps must be passed?


   This is an eight-number problem, and eight-number is a classic BFS problem.
   This question first uses the technique of " turning a circle into a line ". Making the grasshopper jump directly to the empty disk is a bit of a hassle, because there are a lot of grasshoppers jumping. If you look at it the other way around, let the empty disk jump to the position of the grasshopper, it is much simpler, there is only one empty disk jumping. The question gives a circle, which is not easy to deal with. You can "turn the circle into a line". Think of the empty disk as 0, then there are 9 numbers {0, 1, 2, 3, 4, 5, 6, 7, 8}, 9 numbers on a circle, straightened into 9 numbers on a line. This is the eight-number problem, the eight-number has 9 numbers {0,1,2,3,4,5,6,7,8}, it has 9! =362880 permutations, not too many.
   The initial state of this question is "012345678", and the final state is "087654321". Jumping once from the initial state, there are 4 situations in the next state, as shown in the figure.

insert image description here
   Extend each layer with BFS. Each layer means that the grasshopper jumped once, and when it expanded to a certain layer, it found the end point "087654321". The depth of this layer is the number of times the grasshopper jumped.
   Therefore, the eight-number problem is actually a shortest path problem , and BFS is the most suitable.
   If you write a naked BFS for this question, can it run? From step 1 to step 2, there are 4 jumping methods; from step 2 to step 3, there are 4 2 4^242 types;...; step 20, there are4 20 4^{20}42 0 = 1 trillion species.
   It is necessary to judge the weightand judge whether there are repeated jumps. If you jump to a situation that has happened before, you don't need to jump down. There are only 9 in total! = 362880 cases. What is the complexity of the code? At each level, at least 4 and up to 362880 situations can be expanded, and the final calculated answer is 20 levels, so the maximum calculation is 20*362880 = 7,257,600 times. Counting the actual number of calculations in the following C++ code is 1451452 times.
   How to judge the weight? Use STL's map and set to judge the weight, and the efficiency is very good.
   In addition, there is a mathematical method called Cantor Judgment (for detailed explanation of Cantor Judgment, refer to "Introduction to Advanced Algorithm Competition", Tsinghua University Press, Luo Yongjun, Guo Weibin, "4.3.2 Eight Digit Problems"), which isgenerally not used in competitions.
   The following is the code of "Jumping Grasshopper". There are two weight judgment methods: map and set. Please understand the concept of STL map and set by yourself.

1. Map weight judgment

#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;

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));
			}
		}
	}
}
int main(){
    
    
	string s = "012345678";
	q.push(node(s, 0));
//(1) map
	mp[s] = true;
	solve();
	return 0;
}

2. Set judgment weight

#include<bits/stdc++.h>
using namespace std;
struct node{
    
    
	node(){
    
    }
	node(string ss, int tt){
    
    s = ss, t = tt;}
	string s;
	int t;
};

//(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;  //跳到一种情况
//(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));
	solve();
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43914593/article/details/123745160