搜索方法窥探

一,经典搜索(深搜和广搜)与剪枝

int a[62];
bool v[62];
int n;
bool bingo=0;
bool cmp(int a,int b){return a>b?1:0;}
bool dfs(int begin,int left,int now,int max){
    if(left==now)  return 1;
    for(int i=begin;i<n;i++){
        if(v[i]||a[i]>now) continue;
        v[i]=1;
       if(a[i]==now &&dfs(0,left-a[i],max,max)) return 1;
      else if(dfs(begin+1,left-a[i],now-a[i],max)) return 1;
        v[i]=0;
        if(now==max||a[i]==now) return 0;
        while(a[i+1]==a[i])
            i++;
    }
    return 0;
}
int main(){
    int max,sum;
    while(scanf("%d",&n)!=EOF){
        bingo=0;
        max=-1,sum=0;
        if(!n) break;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            if(a[i]>max) max=a[i];
            sum+=a[i];
        }
        int ans;
        sort(a,a+n,cmp);
        memset(v,0,sizeof(v));
        for(ans=max;ans<=sum/2;ans++)
        {
            if(sum%ans!=0) continue;
            if(dfs(0,sum,ans,ans)){
                printf("%d
",ans);
                bingo=1;
                break;
            }
            
        
        }
        if(!bingo) printf("%d
",sum); 
    }
return 0;
}

二,迭代加深搜索

//POJ 3921
//给出一张有向图,问最少删除几个点,能使起点到终点的最短距离大于K
/*
 * 先用bfs找到一条最短路,然后枚举删除每个点。删除点的时候,可以用迭代加深。
 * 先枚举所有删除K个点的情况,如果无解,则枚举删除K+1个点的情况
 */
#define MM 4010
#define MN 100
struct Edge {
    int x, y, next;
} edge[MM];
int head[MN], tot;

int n, m, k;

bool rem[MN]; //false表示该点没删除,true表示该删除了
int path[MN];
int cpath[MN][MN];
queue<int> que;

int ite; //表示迭代次数
int finds; //表示是否找到解

void addline(int u, int v) {
    edge[++tot].next = head[u];
    head[u] = tot;
    edge[tot].x = u, edge[tot].y = v;
}
//在有向图中利用广度优先搜索找路
bool bfs() {
    while (!que.empty())
        que.pop();
    memset(path, 0, sizeof(path));
    que.push(1);
    while (!que.empty()) {
        int v = que.front();
        que.pop();
        for (int i = head[v]; i > 0; i = edge[i].next) {
            if (!path[edge[i].y] && !rem[edge[i].y]) {
                que.push(edge[i].y);
                path[edge[i].y] = edge[i].x;
                if (edge[i].y == n)
                    return 1;
            }
        }
    }
    return 0;
}
void dfs(int deep) {
    if (finds)
        return;
    if (!bfs()) { //如果不可到达,无穷大大于K
        finds = true;
        return;
    }
    int cnt = 0;
    int v = n;
    for (int i = n; v > 1; v = path[v])
        cpath[deep][cnt++] = v;

    if (cnt > k) {
        finds = true;
        return;
    }
    if (deep > ite)
        return; //如果深度到了,也不用找了
    for (int i = 1; i < cnt; i++) { //尝试删除路径上的点
        rem[cpath[deep][i]] = 1;
        dfs(deep + 1);
        rem[cpath[deep][i]] = 0;
    }
}
int solve() {
    finds = 0;
    for (ite = 0; ite <= n; ite++) {
        memset(rem, 0, sizeof(rem));
        dfs(1);
        if (finds)
            return ite;
    }
    return n;
}

三,双向广搜

// POJ 1077 康托展开 双向广搜
#define MAXN 402880
int first[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
unsigned int factorial[11] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
char tran[4];
struct Node {
    int board[9];
    int space;
    int order;
    void getOrder() {
        order = GetPermutationNum(board, 9);
    }
};
int father[2][MAXN];
int ope[2][MAXN];
int dir[4][2] = { { 0, -1 }, { -1, 0 }, { 1, 0 }, { 0, 1 } }; //u, l, r, d
bool checked[2][MAXN];
int matchingStatus;
int matchingQ;
bool BFS(Node begin, Node end) {
    int x, y, dx, dy;
    queue<Node> Q[2];
    Q[1].push(end);
    Q[0].push(begin);
    checked[1][end.order] = 1;
    checked[0][begin.order] = 1;

    father[1][end.order] = -1;
    ope[1][end.order] = -1;
    father[0][begin.order] = -1;
    ope[0][begin.order] = -1;
    while (!Q[0].empty() && !Q[1].empty()) {
        int next;
        if (Q[0].empty())
            next = 1;
        else if (Q[1].empty())
            next = 0;
        else {
            if (Q[0].size() < Q[1].size())
                next = 0;
            else
                next = 1;
        }
        int another = 1 - next;
        Node head = Q[next].front();
        Q[next].pop();
        if (checked[another][head.order]) { // 出来的元素曾经在另一队列里面
            matchingStatus = head.order;
            matchingQ = next;
            return 1;
        } else {
            x = head.space % 3;
            y = head.space / 3;
            for (int i = 0; i < 4; i++) {
                if (i + ope[next][head.order] == 3)
                    continue;
                dx = x + dir[i][0];
                dy = y + dir[i][1];
                Node tmp = head;
                if (dx >= 0 && dx < 3 && dy >= 0 && dy < 3) {
                    swap(tmp.board[tmp.space], tmp.board[dy * 3 + dx]);
                    tmp.space = dy * 3 + dx;
                    tmp.getOrder();
                    if (!checked[next][tmp.order] && solvable(tmp)) {
                        checked[next][tmp.order] = 1;
                        father[next][tmp.order] = head.order;
                        ope[next][tmp.order] = i;
                        Q[next].push(tmp);
                    }
                }
            }
        }
    }
    return 0;
}

四,AStar

#define MAXN 402880
int first[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
char tran[4];
struct Node {
    int board[9];
    int space;
    int order;
    int f, g, h;
    bool operator <(const Node &tmp) const {
        return f < tmp.f;
    }
    void getOrder() {
        order = GetPermutationNum(board, 9);
    }
    void getF() {
        f = g + h;
    }
};
void getH(Node &p) {
    int tmp = 0;
    for (int i = 0; i < 10; i++)
        if (p.board[i] != 9) {
            tmp += abs(p.board[i] % 3 - i % 3) + abs(p.board[i] / 3 - i / 3);
        }
    p.h = tmp * 4; // 1 倍会超时
}
int father[MAXN];
int ope[MAXN];

int dir[4][2] = { { 0, -1 }, { -1, 0 }, { 1, 0 }, { 0, 1 } }; //u, l, r, d
int checked[MAXN]; // 0未访问,1在open,2在close
int openDir[MAXN], closeDir[MAXN];
multiset<Node> open, close;
multiset<Node>::iterator it;
bool BFS(Node end) {
    int x, y, dx, dy;
    open.insert(end);
    checked[end.order] = 1;
    openDir[end.order] = end.f;

    father[end.order] = -1;
    ope[end.order] = -1;
    while (!open.empty()) {
        Node head = *open.begin();
        if (head.order == 0) {
            return 1;
        }
        open.erase(open.begin());
        checked[head.order] = 2;
        closeDir[head.order] = head.f;
        x = head.space % 3;
        y = head.space / 3;
        for (int i = 0; i < 4; i++) {
            if (i + ope[head.order] == 3)
                continue;
            dx = x + dir[i][0];
            dy = y + dir[i][1];
            if (dx >= 0 && dx < 3 && dy >= 0 && dy < 3) {
                Node tmp = head;
                swap(tmp.board[tmp.space], tmp.board[dy * 3 + dx]);
                if (!solvable(tmp))
                    continue;
                tmp.space = dy * 3 + dx;
                tmp.getOrder();
                tmp.g = head.g + 1;
                getH(tmp);
                tmp.getF();
                father[tmp.order] = head.order;
                ope[tmp.order] = i;
                if (checked[tmp.order] == 0) {
                    open.insert(tmp);
                    checked[tmp.order] = 1;
                    openDir[tmp.order] = tmp.f;
                } else if (checked[tmp.order] == 1) {
                    if (tmp.f < openDir[tmp.order]) {
                        openDir[tmp.order] = tmp.f;
                    }
                } else if (checked[tmp.order] == 2) {
                    if (tmp.f < closeDir[tmp.order]) {
                        open.insert(tmp);
                        openDir[tmp.order] = tmp.f;
                        checked[tmp.order] = 1;
                    }
                }
            }
        }
    }
    return 0;
}

 五,DFSID

#define MM 4010
#define MN 100
struct Edge {
    int x, y, next;
} edge[MM];
int head[MN], tot;

int n, m, k;

bool rem[MN]; //false表示该点没删除,true表示该删除了
int path[MN];
int cpath[MN][MN];
queue<int> que;

int ite; //表示迭代次数
int finds; //表示是否找到解

void addline(int u, int v) {
    edge[++tot].next = head[u];
    head[u] = tot;
    edge[tot].x = u, edge[tot].y = v;
}
//在有向图中利用广度优先搜索找路
bool bfs() {
    while (!que.empty())
        que.pop();
    memset(path, 0, sizeof(path));
    que.push(1);
    while (!que.empty()) {
        int v = que.front();
        que.pop();
        for (int i = head[v]; i > 0; i = edge[i].next) {
            if (!path[edge[i].y] && !rem[edge[i].y]) {
                que.push(edge[i].y);
                path[edge[i].y] = edge[i].x;
                if (edge[i].y == n)
                    return 1;
            }
        }
    }
    return 0;
}
void dfs(int deep) {
    if (finds)
        return;
    if (!bfs()) { //如果不可到达,则不用找了
        finds = true;
        return;
    }
    int cnt = 0;
    int v = n;
    for (int i = n; v > 1; v = path[v])
        cpath[deep][cnt++] = v;

    if (cnt > k) {
        finds = true;
        return;
    }
    if (deep > ite)
        return; //如果深度到了,也不用找了
    for (int i = 1; i < cnt; i++) { //尝试删除路径上的点
        rem[cpath[deep][i]] = 1;
        dfs(deep + 1);
        rem[cpath[deep][i]] = 0;
    }
}
int solve() {
    finds = 0;
    for (ite = 0; ite <= n; ite++) {
        memset(rem, 0, sizeof(rem));
        dfs(1);
        if (finds)
            return ite;
    }
    return n;
}

六.博弈树的极大极小算法与Alpha –beta剪枝

《博弈知识》

题意:给出一个4*4的棋盘,x和o两人轮流放。先放够连续四个的赢。给定一个局面,下一个轮到x放。问x是否有必胜策略?若有,输出能够赢的该下子的坐标。

思路:

1)Maxfind(Min):每次放x,若得到的Max大于等于Min,则直接返回Max。

(2)Minfind(Max)类似;

(3)因此,枚举第一个人放的位置,Minfind,返回的是INF则胜利。

#include <iostream>
using namespace std;
#define INF 0x3fffffff
int state[5][5], chess, xi, xj;
bool over(int x, int y) { //判断一个局面是否是结束局面
    int tot = 0;
    //横向判断
    for (int i = 0; i < 4; i++)
        if (state[x][i] == 'o')
            tot++;
        else if (state[x][i] == 'x')
            tot--;
    if (tot == 4 || tot == -4)
        return 1;
    tot = 0;
    //纵向判断
    for (int i = 0; i < 4; i++)
        if (state[i][y] == 'o')
            tot++;
        else if (state[i][y] == 'x')
            tot--;
    if (tot == 4 || tot == -4)
        return 1;
    tot = 0;
    //主对角线判断
    for (int i = 0; i < 4; i++)
        if (state[i][i] == 'o')
            tot++;
        else if (state[i][i] == 'x')
            tot--;
    if (tot == 4 || tot == -4)
        return 1;
    tot = 0;
    //辅对角线判断
    for (int i = 0; i < 4; i++)
        if (state[i][3 - i] == 'o')
            tot++;
        else if (state[i][3 - i] == 'x')
            tot--;
    if (tot == 4 || tot == -4)
        return 1;
    return 0;
}
int minSearch(int, int, int);
int maxSearch(int x, int y, int Min) {
//    printf("max  %d
", Min);
    int tmp, Max = -INF;
    if (over(x, y))
        return Max;
    if (chess == 16)
        return 0;
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (state[i][j] == '.') {
                state[i][j] = 'x';
                chess++;
                tmp = minSearch(i, j, Max);
                chess--;
                state[i][j] = '.';
                Max = max(Max, tmp);
                if (Max >= Min)
                    return Max;
            }
    return Max;
}
int minSearch(int x, int y, int Max) {
//    printf("min  %d
", Max);
    int tmp, Min = INF;
    if (over(x, y))
        return Min;
    if (chess == 16)
        return 0;
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (state[i][j] == '.') {
                state[i][j] = 'o';
                chess++;
                tmp = maxSearch(i, j, Min);
                chess--;
                state[i][j] = '.';
                Min = min(Min, tmp);
                if (Min <= Max)
                    return Min;
            }
    return Min;
}
bool solve() {
    int tmp, Max = -INF;
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (state[i][j] == '.') {
                state[i][j] = 'x';
                chess++;
                tmp = minSearch(i, j, Max);
                chess--;
                state[i][j] = '.';
                Max = max(Max, tmp);
                if (Max == INF) {
                    printf("(%d,%d)
", i, j);
                    return 1;
                }
            }
    return 0;
}
int main() {
//    freopen("data3.txt", "r", stdin);
    char OP;
    while (scanf("%c", &OP) && OP != '$') {
        getchar();
        chess = -4;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                state[i][j] = getchar();
                if (state[i][j] != '.')
                    chess++;
            }
            getchar();
        }
        if (chess < 4) {  //强力剪枝
            printf("#####
");
            continue;
        }
        if (!solve())
            printf("#####
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/updateofsimon/p/3405701.html