王道机试指南搜索

例题9.1玛雅人的密码(清华大学上机)
利用一个mp来标记是否出现过,之后进行BFS,且每一次shift之后mp都将加1

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<vector>
#include<map> 
using namespace std;
map<string, int> mp;//记录每一个字符的交换次数 
queue<string> que;//用于bfs的队列 
int n;
string s;
bool has_2012(string s){ //判断是否含有2012 
    for(int i = 0; i < n - 3; i++){
        if(s[i] == '2' && s[i+1] == '0' && s[i+2] == '1' && s[i+3] == '2')
            return true;
    }
    return false;
}
string shift(string s, int i){//用来转换字符串 , i位与i+1交换 
        char temp = s[i];
        s[i] = s[i+1];
        s[i+1] = temp;
        return s;
}
int bfs(string s){
    string newstr;
    mp.clear();
    while(!que.empty()) que.pop();//清空队列,队列没有clear()函数 
    que.push(s);//初始字符串入队 
    mp[s] = 0;//初始字符串交换次数为0 
    while(!que.empty()){
        s = que.front();
        que.pop();//取出队首 
        for(int i = 0; i < n - 1; i++){
            newstr = shift(s, i);
            if(mp.find(newstr) == mp.end()){//字符没有出现过 
                mp[newstr] = mp[s] + 1;//出现了且交换次数多于他爹的交换次数 
                if(has_2012(newstr)) return mp[newstr];
                else que.push(newstr);
            }
        }
    }
    return -1;
}

int main(){
    while(cin >> n >> s){
        if(has_2012(s)) cout << 0 << endl;
        else cout << bfs(s) << endl;
    }
    return 0;
}  

习题9.2神奇的口袋(北京大学上机)
因为不可以重复,所以可以不用visit数组,直接使用pos来进行遍历,递归就可以得到结果。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n;
vector<int> v;
int kind;
void dfs(int sum, int pos){
    if(sum == 40){
        kind++;
        return;
    }
    if(sum > 40) return;
    for(int i = pos; i < n; i++){
            dfs(v[i] + sum, i+1);
    }
} 
int main(){
    while(cin >> n){
        kind = 0;
        v.clear();
        for(int i = 0; i < n; i++){//输入n个数到v 
            int temp;
            cin >> temp;
            v.push_back(temp);
        }
        dfs(0, 0);
        cout << kind << endl;
    }
    return 0;
}  

习题9.2八皇后(北京大学上机)
注意理解题目中的递归思想,剪枝的技巧

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<string>
#include<cmath>
#include<stdlib.h>
using namespace std;
int p[9];
vector<int> vi;
bool hashtable[9];//用来标记列是否放入 
void generatep(int row){//从第index行开始填入 
    if(row == 9){//表示找到一个结果,将其转化为整数存入vi
        int sum = 0;
        for(int i = 1; i <= 8; i++){
            sum += p[i] * pow(10, 8 - i);
        }
        vi.push_back(sum);
        return;
    }
    
    for(int x = 1; x <= 8; x++){//遍历第x列 
        if(hashtable[x] == false){
            bool flag = true;
            /*for循环用来剪枝*/ 
            for(int pre = 1; pre < row; pre++){//遍历之前填入的结点
            //x为index的列,p[pre]为pre的列 
                if(abs(row - pre) == abs(x - p[pre])){//对角线上的结点相同 
                    flag = false;
                    break;
                }
            }
            if(flag){//可以填入,直接向下填入,递归访问 
                p[row] = x;
                hashtable[x] = true;
                generatep(row+1);
                hashtable[x] = false;//回溯还原 
            }
        }
    }
}
int main(){
    int b;//根本就没有case个数的输入 
    while(cin >> b){
        generatep(1); 
        sort(vi.begin(), vi.end());
        cout << vi[b - 1]<< endl;
    }
    return 0;
}