• 魔术球问题(最大流,最小路径点覆盖,二分图,网络流24题)


    题意

    假设有(n)根柱子,现要按下述规则在这(n)根柱子中依次放入编号为(1,2,3,dots)的球。

    • 每次只能在某根柱子的最上面放球。

    • 在同一根柱子中,任何 (2) 个相邻球的编号之和为完全平方数。

    试设计一个算法,计算出在 (n) 根柱子上最多能放多少个球。

    思路

    典型的最小路径点覆盖问题!

    本题可以采用枚举的方法,一个数一个数的枚举,把点加到图中,跑最大流,直到需要的柱子数大于给定数量为止。

    注意,最后还需要跑一遍最大流,因为枚举的最后一个点是刚好不行的点,因此需要将那个点去掉。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int N = 3210, M = 500010, inf = 1e8;
    
    int n, S, T;
    int h[N], e[M], ne[M], f[M], idx;
    int cur[N], d[N];
    int pre[N], sec[N];
    bool is_f[N];
    
    void add(int a, int b, int c)
    {
        e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++;
        e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
    }
    
    bool bfs()
    {
        memset(d, -1, sizeof(d));
        queue<int> que;
        que.push(S);
        d[S] = 0, cur[S] = h[S];
        while(que.size()) {
            int t = que.front();
            que.pop();
            for(int i = h[t]; ~i; i = ne[i]) {
                int ver = e[i];
                if(d[ver] == -1 && f[i]) {
                    d[ver] = d[t] + 1;
                    cur[ver] = h[ver];
                    if(ver == T) return true;
                    que.push(ver);
                }
            }
        }
        return false;
    }
    
    int find(int u, int limit)
    {
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; ~i && limit > flow; i = ne[i]) {
            cur[u] = i;
            int ver = e[i];
            if(d[ver] == d[u] + 1 && f[i]) {
                int t = find(ver, min(f[i], limit - flow));
                if(!t) d[ver] = -1;
                f[i] -= t, f[i ^ 1] += t, flow += t;
            }
        }
        return flow;
    }
    
    int dinic()
    {
        int res = 0, flow;
        while(bfs()) {
            while(flow = find(S, inf)) {
                res += flow;
            }
        }
        return res;
    }
    
    void get()
    {
        for(int i = 0; i < idx; i += 2) {
            int b = e[i], a = e[i ^ 1];
            if(a != S && b != T) {
                if(!f[i]) {
                    pre[(b - 1) / 2] = a / 2;
                    sec[a / 2] = (b - 1) / 2;
                }
            }
        }
    }
    
    void output(int u)
    {
        printf("%d", u);
        while(sec[u]) {
            printf(" %d", sec[u]);
            u = sec[u];
        }
        puts("");
    }
    
    int main()
    {
        scanf("%d", &n);
        memset(h, -1, sizeof(h));
        S = 0, T = 1;
        for(int i = 1; i <= 3200; i ++) {
            for(int j = 1; j <= 1600; j ++) {
                if(j * j == i) {
                    is_f[i] = true;
                    break;
                }
            }
        }
        int ans = 1;
        for(int i = 1; i <= 1600; i ++) {
            for(int j = 0; j < idx; j += 2) {
                f[j] += f[j ^ 1];
                f[j ^ 1] = 0;
            }
            add(S, 2 * i, 1);
            add(2 * i + 1, T, 1);
            for(int j = 1; j <= i - 1; j ++) {
                if(is_f[i + j]) {
                    add(2 * j, 2 * i + 1, 1);
                }
            }
            int res = dinic();
            if(i - res > n) {
                printf("%d
    ", i - 1);
                ans = i - 1;
                break;
            }
        }
        memset(h, -1, sizeof(h));
        idx = 0;
        for(int i = 1; i <= ans; i ++) {
            add(S, 2 * i, 1);
            add(2 * i + 1, T, 1);
            for(int j = 1; j <= i - 1; j ++) {
                if(is_f[i + j]) {
                    add(2 * j, 2 * i + 1, 1);
                }
            }
        }
        dinic();
        get();
        for(int i = 1; i <= ans; i ++) {
            if(!pre[i]) {
                output(i);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    一篇就搞懂Mysql存储引擎和索引的文章
    ShardedJedisPipeline中sync()和syncAndReturnAll()区别
    17.win10安装Nginx及负载均衡配置,实现代理访问内网机器
    iDempiere 使用指南 系统安装 以及 virtualbox虚拟机下载
    程序员学数学【整理】
    element 表单校验
    draggable 拖拽列表排序(指定被拖拽的子元素)
    导出多个表的excel文件
    js自定义鼠标的图片
    table 导出简单的excel
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14414875.html
Copyright © 2020-2023  润新知