• 搜索训练


    1.HDU 2208

    给小朋友分组,两两小朋友都喜欢对方才能分一组(因此既不是并查集,也不是强连通),数据多小啊,搜索先来一发。

    更好的思路是root[i]=J 表示i属于j组,找到每个root[i]==i的与新元素判断是否都在集合中,是就加入或不加入,不是就新产生一组。

    我还是比较喜欢用STL

    #include <cstdio>
    #include <vector>
    using namespace std;
    int G[13][13];
    int n, m;
    bool flag;
    vector<int> part[22];
    void dfs(int num, int team) {
        if (flag)
            return;
        if (team > m)
            return;
        if (num == n) {
            flag = 1;
            return;
        }
        for (int i = 0; i < team; i++) {
            int j;
            for (j = 0; j < part[i].size(); j++)
                if (!G[num][part[i][j]])
                    break;
            if (j == part[i].size()) {
                part[i].push_back(num);
                dfs(num + 1, team);
                part[i].pop_back();
            }
            if (flag)
                break;
        }
        part[team].clear();
        part[team].push_back(num);
        dfs(num + 1, team + 1);
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        int tn, j;
        while (~scanf("%d%d", &n, &m)) {
            flag = 0;
            memset(G, 0, sizeof(G));
            for (int i = 0; i < n; i++) {
                part[i].clear();
                scanf("%d", &tn);
                while (tn--) {
                    scanf("%d", &j);
                    G[i][j] = 1;
                }
            }
            part[0].push_back(0);
            dfs(1, 1);
            if (flag)
                puts("YES");
            else
                puts("NO");
        }
        return 0;
    }

     2.HDU 1258

    这个太简单了,主要是去重就是可以一个一个选,但只要开始不选,相同的后面就都不能选了

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    vector<int> ans;
    int cnt;
    int n, tot, num[1009];
    void dfs(int pos, int sum) {
        if (sum > tot)
            return;
        if (sum == tot) {
            cnt++;
            printf("%d", ans[0]);
            for (int i = 1; i < ans.size(); i++)
                printf("+%d", ans[i]);
            puts("");
            return;
        }
        if (pos >= n)
            return;
        ans.push_back(num[pos]);
        dfs(pos + 1, sum + num[pos]);
        ans.pop_back();
        while (pos + 1 < n && num[pos] == num[pos + 1])
            pos++;
        dfs(pos + 1, sum);
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        while (~scanf("%d%d", &tot, &n) && n) {
            printf("Sums of %d:
    ", tot);
            cnt = 0;
            for (int i = 0; i < n; i++)
                scanf("%d", &num[i]);
            sort(num, num + n);
            reverse(num, num + n);
            dfs(0, 0);
            if (!cnt)
                puts("NONE");
        }
        return 0;
    }

     3.HDU 4607

    就是个树的直径巧妙应用

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define MAXN 100005
    int n, m;
    int tot, head[MAXN];
    struct Edge {
        int v, next;
    } edge[MAXN * 2];
    void init() {
        tot = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int u, int v) {
        edge[tot].v = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    void dfs(int u, int fa, int deep, int &max_len, int &max_id) {
        if (head[u] == -1)
            return;
        if (deep > max_len)
            max_len = deep, max_id = u;
        for (int i = head[u]; i != -1; i = edge[i].next)
            if (edge[i].v != fa)
                dfs(edge[i].v, u, deep + 1, max_len, max_id);
    }
    int tree_2r() {
        int max_len = -1, max_id;
        dfs(1, -1, 0, max_len, max_id);
        max_len = -1;
        dfs(max_id, -1, 0, max_len, max_id);
        return max_len;
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        int T, u, v;
        scanf("%d", &T);
        while (T--) {
            scanf("%d%d", &n, &m);
            init();
            for (int i = 1; i < n; i++) {
                scanf("%d%d", &u, &v);
                addedge(u, v);
                addedge(v, u);
            }
            int len = tree_2r();
            int q;
            while (m--) {
                scanf("%d", &q);
                if (q <= len + 1)
                    printf("%d
    ", q - 1);
                else
                    printf("%d
    ", len + (q - len - 1) * 2);
            }
        }
        return 0;
    }

     4.HDU 1175

    做了好长时间,主要是对BFS理解不够深入,BFS的访问次序只是路径长度,相同的有几种,而路径短的可能拐了好几个弯,用过vis记录每个点最小拐弯数,次数更少的也要进入队列。还有考虑这题可以用Astar尝试做下。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <queue>
    using namespace std;
    int n, m;
    int G[1009][1009];
    int vis[1009][1009];
    struct Node {
        int x, y;
        int aim, cnt;
        Node() {
        }
        Node(int _x, int _y) {
            x = _x, y = _y, aim = -1, cnt = -1;
        }
        bool operator ==(const Node &tmp) const {
            return tmp.x == x && tmp.y == y;
        }
        bool operator !=(const Node &tmp) const {
            return tmp.x != x || tmp.y != y;
        }
    };
    int dir[4][2] = { 0, -1, -1, 0, 1, 0, 0, 1 };
    bool BFS(Node s, Node t) {
        if (s == t)
            return 0;
        queue<Node> Q;
        Q.push(s);
        while (!Q.empty()) {
            Node cur = Q.front();
            Q.pop();
            Node tmp = cur;
            for (int j = tmp.aim; j < tmp.aim + 4; j++) {
                int i = (j + 4) % 4;
                if (i + tmp.aim == 3)
                    continue;
                cur.x = tmp.x + dir[i][0], cur.y = tmp.y + dir[i][1];
                if (cur.x > n || cur.y > m || cur.x <= 0 || cur.y <= 0)
                    continue;
                if (G[cur.x][cur.y] && cur != t)
                    continue;
                if (tmp.aim != i)
                    cur.cnt = tmp.cnt + 1, cur.aim = i;
                if (cur.cnt > 2)
                    continue;
                if (cur == t)
                    return 1;
                if (vis[cur.x][cur.y] > cur.cnt) {
                    vis[cur.x][cur.y] = cur.cnt;
                    Q.push(cur);
                }
            }
        }
        return 0;
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        int q, x1, y1, x2, y2;
        while (~scanf("%d%d", &n, &m) && m && n) {
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= m; j++)
                    scanf("%d", &G[i][j]);
            scanf("%d", &q);
            while (q--) {
                memset(vis, 0x3f, sizeof(vis));
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                if (!G[x1][y1] || !G[x2][y2] || G[x1][y1] != G[x2][y2]
                        || !BFS(Node(x1, y1), Node(x2, y2)))
                    puts("NO");
                else
                    puts("YES");
            }
        }
        return 0;
    }

     5. POJ 1054

    坐标哈希的裸题,要有最优化剪枝的

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define MAXN 5009
    #define hash_size 20100
    
    struct Node {
        int x, y;
        Node() {
        }
        Node(int _x, int _y) :
                x(_x), y(_y) {
        }
        bool operator <(const Node &tmp) const {
            return (x == tmp.x) ? y < tmp.y : x < tmp.x;
        }
    } point[MAXN];
    int head[hash_size];
    int next[MAXN];
    
    int getHash(Node p) {
        int h = hash_size;
        return ((p.x * 20001 + p.y) % h + h) % h;
    }
    bool find(int x, int y) {
        int f = getHash(Node(x, y));
        for (int i = head[f]; i != -1; i = next[i])
            if (point[i].x == x && point[i].y == y)
                return 1;
        return 0;
    }
    int R, C, n;
    bool check(Node tp) {
        return tp.x <= 0 || tp.x > R || tp.y <= 0 || tp.y > C;
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        while (~scanf("%d%d", &R, &C)) {
            scanf("%d", &n);
            memset(head, -1, sizeof(head));
            for (int i = 0; i < n; i++)
                scanf("%d%d", &point[i].x, &point[i].y);
            sort(point, point + n - 1);
            for (int i = 0; i < n; i++) {
                int f = getHash(point[i]);
                next[i] = head[f];
                head[f] = i;
            }
            int ans = 2, dx, dy, cnt;
            Node tp;
            for (int i = 0; i < n - 1; i++) {
                for (int j = i + 1; j < n; j++) {
                    cnt = 1;
                    dx = point[j].x - point[i].x;
                    dy = point[j].y - point[i].y;
                    tp.x = point[i].x - dx, tp.y = point[i].y - dy;
                    if (!check(tp))
                        continue;
                    if (dx > R / 2 || dy > C / 2)
                        continue;
                    tp.x = point[i].x + (ans - 1) * dx, tp.y = point[i].y
                            + (ans - 1) * dy;
                    if (check(tp))
                        continue;
                    tp.x = point[j].x, tp.y = point[j].y;
                    bool flag = 0;
                    while (find(tp.x, tp.y)) {
                        tp.x += dx, tp.y += dy;
                        cnt++;
                        if (check(tp)) {
                            flag = 1;
                            break;
                        }
                    }
                    if (flag && cnt > 2)
                        ans = max(ans, cnt);
                }
            }
            if (ans > 2)
                printf("%d
    ", ans);
            else
                puts("0");
        }
        return 0;
    }

     6. HDU 1813

    比较容易想的DFSID问题,首先求所有点到边界的最短距离的最大值开始为深度DFS,每次把没移到边界的点按一个方向挪进行搜索,采用计算最大最短距离作为剪枝。

    搞了2小时了还是T,应该是一种情况的死循环。先贴T的代码

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    using namespace std;
    int G[19][19];
    int N;
    int dis[19][19];
    int dir[4][2] = { 0, 1, -1, 0, 1, 0, 0, -1 };
    struct Point {
        int x, y;
        int yes;
        int len, aim;
        Point() {
        }
        Point(int _x, int _y) :
                x(_x), y(_y) {
            yes = 0;
        }
        Point(int _x, int _y, int _len, int _aim) :
                x(_x), y(_y), len(_len), aim(_aim) {
        }
    };
    inline bool out(int x, int y) {
        if (G[x][y])
            return 1;
        if (x < 1 || x > N || y < 1 || y > N)
            return 1;
        return 0;
    }
    inline bool ok(int x, int y) {
        if (x == 1 || x == N || y == 1 || y == N)
            return 1;
        return 0;
    }
    queue<Point> Q;
    int cnt;
    void BFS(int x, int y, int aim) {
        if (out(x, y))
            return;
        dis[x][y] = 0;
        while (!Q.empty())
            Q.pop();
        Q.push(Point(x, y, 0, aim));
        Point cur, tmp;
        while (!Q.empty()) {
            cur = Q.front();
            Q.pop();
            for (int i = 0; i < 4; i++) {
                if (cur.aim + i == 3)
                    continue;
                tmp.x = cur.x + dir[i][0];
                tmp.y = cur.y + dir[i][1];
                if (out(tmp.x, tmp.y))
                    continue;
                if (dis[tmp.x][tmp.y] > cur.len + 1) {
                    tmp.len = dis[tmp.x][tmp.y] = cur.len + 1;
                    tmp.aim = i;
                    Q.push(tmp);
                }
            }
        }
    }
    inline int Astar(Point SET[], int cnt) {
        int Min_deep = -1;
        for (int i = 0; i < cnt; i++) {
            Min_deep = max(Min_deep, dis[SET[i].x][SET[i].y]);
        }
        return Min_deep;
    }
    bool flag;
    int ans[109];
    void DFSID(Point SET[], int deep, int last) {
        if (flag)
            return;
        if (last == 0) {
            flag = 1;
            return;
        }
        if (deep == 0 || Astar(SET, cnt) > deep)
            return;
        int last_t = last;
        Point point_t[101];
        for (int i = 0; i < cnt; i++) {
            point_t[i] = SET[i];
        }
        for (int d = 0; d < 4; d++) {
            for (int i = 0; i < cnt; i++) {
                if (SET[i].yes)
                    continue;
                if (G[SET[i].x + dir[d][0]][SET[i].y + dir[d][1]])
                    continue;
                point_t[i].x = SET[i].x + dir[d][0];
                point_t[i].y = SET[i].y + dir[d][1];
                if (ok(point_t[i].x, point_t[i].y)) {
                    point_t[i].yes = deep;
                    last_t--;
                }
            }
            ans[deep] = d;
            DFSID(point_t, deep - 1, last_t);
            if (flag)
                return;
            last_t = last;
        }
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        bool p = 0;
        while (~scanf("%d", &N)) {
            if (p)
                puts("");
            p = 1;
            getchar();
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= N; j++)
                    G[i][j] = getchar() - '0';
                getchar();
            }
            if (N < 3) {
                continue;
            }
            memset(dis, 0x7f, sizeof(dis));
            for (int i = 1; i <= N; i++) {
                BFS(1, i, 3);
                BFS(N, i, 0);
                BFS(i, 1, 2);
                BFS(i, N, 1);
            }
            Point SET[109];
            cnt = 0;
            int Min_deep = -1;
            for (int i = 1; i <= N; i++)
                for (int j = 1; j <= N; j++)
                    if (dis[i][j] != 2139062143 && !ok(i, j)) {
                        Min_deep = max(Min_deep, dis[i][j]);
                        SET[cnt++] = Point(i, j);
                    }
            if (Min_deep == -1)
                continue;
            for (int deep = Min_deep;; deep++) {
                flag = 0;
                DFSID(SET, deep, cnt);
                if (flag) {
                    for (int i = deep; i > 0; i--) {
                        if (ans[i] == 0)
                            puts("east");
                        else if (ans[i] == 1)
                            puts("north");
                        else if (ans[i] == 2)
                            puts("south");
                        else if (ans[i] == 3)
                            puts("west");
                    }
                    break;
                }
            }
        }
        return 0;
    }

     7.UVA 10453

    添加最少个字母使串为回文,记忆化搜索

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    #define MAXN 1009
    #define INF 0x3fffffff
    int dp[MAXN][MAXN];
    char str[MAXN];
    int dfs(int left, int right) {
        if (left >= right)
            return dp[left][right] = 0;
        if (dp[left][right] != INF)
            return dp[left][right];
        if (str[left] == str[right])
            return dp[left][right] = min(dfs(left + 1, right - 1),
                    min(dfs(left + 1, right), dfs(left, right - 1)) + 1);
        return dp[left][right] = min(dfs(left + 1, right), dfs(left, right - 1)) + 1;
    }
    void print(int left, int right) {
        if (left > right)
            return;
        if (left == right) {
            putchar(str[left]);
            return;
        }
        if (str[left] == str[right]) {
            putchar(str[left]);
            print(left + 1, right - 1);
            putchar(str[right]);
            return;
        }
        if (dp[left + 1][right] + 1 == dp[left][right]) {
            putchar(str[left]);
            print(left + 1, right);
            putchar(str[left]);
            return;
        }
        putchar(str[right]);
        print(left, right - 1);
        putchar(str[right]);
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        while (~scanf("%s", str)) {
            int len = strlen(str);
            for (int i = 0; i < len; i++)
                for (int j = i; j < len; j++)
                    dp[i][j] = INF;
            printf("%d ", dfs(0, len - 1));
            print(0, len - 1);
            puts("");
        }
        return 0;
    }

     8. HDU 2485

    通过搜索枚举各种删除点方案,通过BFS找到一条路径,删除这条路径的每个点后DFS看能不能再找到可达路径,找到再枚举删除点,加上最优化剪枝

    这题学到了BFS在状态中记录路径的姿势

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define MAXN 55
    #define INF 0x3f3f3f3f
    using namespace std;
    
    int n, m, k, ans, tot;
    int head[MAXN];
    bool vis[MAXN], del[MAXN];
    struct Node {
        int v;
        int next;
    } edge[4005];
    struct Point {
        int x, c;
        int path[MAXN];
    } cur;
    
    void addedge(int u, int v) {
        edge[tot].v = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    bool bfs() {
        queue<Point> Q;
        memset(vis, 0, sizeof(vis));
        cur.x = 1;
        cur.c = 0;
        vis[1] = 1;
        Q.push(cur);
        Point tmp;
        while (!Q.empty()) {
            cur = Q.front();
            Q.pop();
            for (int i = head[cur.x]; i != -1; i = edge[i].next) {
                int v = edge[i].v;
                if (del[v])
                    continue;
                if (!vis[v] && cur.c < k) {
                    vis[v] = 1;
                    if (v == n) {
                        return 1;
                    }
                    tmp = cur;
                    tmp.x = v;
                    tmp.path[tmp.c++] = v;
                    Q.push(tmp);
                }
            }
        }
        return 0;
    }
    void dfs(int num) {
        if (num >= ans) //最优化剪枝
            return;
        if (!bfs()) {
            ans = num;
            return;
        }
        Point tmp = cur;
        for (int i = 0; i < tmp.c; i++) {
            int v = tmp.path[i];
            del[v] = 1;
            dfs(num + 1);
            del[v] = 0;
        }
    }
    int main() {
    //    freopen("data3.txt", "r", stdin);
        int u, v;
        while (scanf("%d%d%d", &n, &m, &k) && n && m && k) {
            tot = 0;
            memset(head, -1, sizeof(head));
            for (int i = 0; i < m; i++) {
                scanf("%d%d", &u, &v);
                addedge(u, v);
            }
            ans = INF;
            memset(del, 0, sizeof(del));
            dfs(0);
            printf("%d
    ", ans);
        }
        return 0;
    }

    9. HDU 4090

    对每个局面枚举一个操作,深搜加最优化剪枝。这里学到了用队列配合保存状态,对每个局面有局面备份和走过记录,还有位置转化很难写

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<string>
    using namespace std;
    
    int a[10][10];
    int n, m, k;
    int ans;
    int cnt[10];
    
    int dx[] = { 0, -1, 1, 0, -1, 1, -1, 1 };
    int dy[] = { -1, 0, 0, 1, 1, 1, -1, -1 };
    
    struct Point {
        int x, y;
    } Q[10000];
    int len;
    int cnt_num(int x, int y, bool vis[][10]) {
        len = 1;
        Point tmp, cur;
        int front = 0, rear = 0;
        cur.x = x;
        cur.y = y;
        Q[rear++] = cur;
        vis[x][y] = 1;
        while (front < rear) {
            cur = Q[front++];
            for (int d = 0; d < 8; d++) {
                tmp = cur;
                tmp.x += dx[d];
                tmp.y += dy[d];
                if (a[tmp.x][tmp.y] == a[x][y] && !vis[tmp.x][tmp.y]) {
                    vis[tmp.x][tmp.y] = 1;
                    len++;
                    Q[rear++] = tmp;
                }
            }
        }
        return len;
    }
    inline void save(int sa[][10]) {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                sa[i][j] = a[i][j];
    }
    inline void recover(int sa[][10]) {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                a[i][j] = sa[i][j];
    }
    void move() { //删和调整位置
        for (int i = 0; i < len; i++)
            a[Q[i].x][Q[i].y] = 0;
        for (int i = 1; i <= n - 1; i++) //向下沉
            for (int j = 1; j <= m; j++) {
                if (a[i][j] && !a[i + 1][j]) {
                    int x;
                    for (x = i; a[x][j]; x--)
                        a[x + 1][j] = a[x][j];
                    a[x + 1][j] = 0;
                }
            }
        for (int j = m; j >= 1; j--) {
            bool flag = 1;
            for (int i = 1; i <= n; i++)
                if (a[i][j])
                    flag = 0;
            if (flag) {
                for (int r = 1; r <= n; r++) {
                    int p, k;
                    for (p = m; p > j; p--) //找到右数第一个位置p
                        if (a[r][p])
                            break;
                    if (p == j)
                        continue;
                    for (k = j; k < p; k++)
                        a[r][k] = a[r][k + 1];
                    a[r][k] = 0;
                }
            }
        }
    }
    inline int get_H() { //剩余个数最优化情况
        int sum = 0;
        for (int i = 1; i <= k; i++) {
            if (cnt[i] >= 3)
                sum += cnt[i] * cnt[i];
        }
        return sum;
    }
    void dfs(int score) { //通过深搜每一次操作
        ans = max(ans, score);
        if (get_H() + score <= ans) //预测函数剪枝
            return;
        bool vis[10][10] = { 0 }; //与BFS传参保证这次枚举操作不多次枚举相同连通块
        int a_backup[10][10];
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                if (a[i][j] == 0 || vis[i][j])
                    continue;
                int s = cnt_num(i, j, vis);
                if (s < 3)
                    continue;
                save(a_backup);
                cnt[a[i][j]] -= s;
                move();
                dfs(score + s * s);
                recover(a_backup);
                cnt[a[i][j]] += s;
            }
    }
    int main() {
    //    freopen("data_tmp.txt", "r", stdin);
        while (~scanf("%d%d%d", &n, &m, &k)) {
            memset(a, 0, sizeof(a));
            memset(cnt, 0, sizeof(cnt));
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                    scanf("%d", &a[i][j]);
                    cnt[a[i][j]]++;
                }
            }
            ans = -1;
            dfs(0);
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    1 说在前面的一些话,给想学习编程的人
    springboot使用api操作HBase之shell
    HBase的安装及使用
    spring boot 多数据源加载原理
    架构师之路
    Libra和中国央行数字货币(DCEP)的对比
    微博feed系统的推(push)模式和拉(pull)模式和时间分区拉模式架构探讨
    海底光缆知识科普
    jmeter安装配置教程及使用
    CountDownLatch 部分加载和同时并发业务。
  • 原文地址:https://www.cnblogs.com/updateofsimon/p/3408632.html
Copyright © 2020-2023  润新知