zoukankan      html  css  js  c++  java
  • 搜索方法窥探

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

    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;
    }
  • 相关阅读:
    dp
    数学分析 + 容斥原理
    容斥
    并查集
    矩阵hash + KMP
    扫描线
    位运算
    2015 Multi-University Training Contest 5 1009 MZL's Border
    iOS ZipArchive文件解压缩
    iOS GCD倒计时
  • 原文地址:https://www.cnblogs.com/updateofsimon/p/3405701.html
Copyright © 2011-2022 走看看