zoukankan      html  css  js  c++  java
  • 洛谷 P2765 魔术球问题 (dinic求最大流,最小边覆盖)

    P2765 魔术球问题

    题目描述

    «问题描述:

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

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

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

    试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。

    «编程任务:

    对于给定的n,计算在n根柱子上最多能放多少个球。

    输入格式

    第1 行有1个正整数n,表示柱子数。

    输出格式

    程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。

    输入输出样例

    输入 #1复制

    4
    

    输出 #1复制

    11
    1 8
    2 7 9
    3 6 10
    4 5 11
    

    说明/提示

    4<=n<=55

    思路:

    首先知道放球的个数和柱子的个数是成正相关的,

    一直增加球,对于每一个球i,将比其小的,能和其相加为平方数的,统一连中间边。

    之所以叫中间边,是因为这题要拆点,设源点和汇点分别为S和T。

    将每一个点i,拆为 Xi,Yi,

    每一个点将其S与Xi连接,Yi与T连接,

    中间点就是如果i节点和j节点相连接,

    就Xi 与Yj,相连,。以上讲到的边,流量全为1.

    当num个数建立的容量网络的最小边覆盖x>n时,即n个柱子无法覆盖掉num个数时,

    结束加边操作,此时num-1,就是N个柱子能覆盖到的最大数字。

    在dinic算法中增光路的过程中,记录每一个v,增广的下一个节节点u。

    一路链状输出就是方法。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define sz(a) int(a.size())
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
    #define du2(a,b) scanf("%d %d",&(a),&(b))
    #define du1(a) scanf("%d",&(a));
    using namespace std;
    typedef long long ll;
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
    ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
    void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    
    inline void getInt(int* p);
    const int maxn = 1000010;
    const int inf = 0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    const int INF = (1 << 30);
    const int MAXN = 400000;
    int idx = 0, e[MAXN], f[MAXN], ne[MAXN], h[100000];
    void add(int a, int b, int c) {
        e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx++;
        e[idx] = a, ne[idx] = h[b], f[idx] = 0, h[b] = idx++;
    }
    int S, T, ch[MAXN], q[MAXN], nex[MAXN];
    bool tell() {
        memset(ch, -1, sizeof(ch));
        int head = 0, tail = 0;
        ch[q[0] = S] = 0;
        while (head <= tail) {
            int t = q[head++];
            for (int i = h[t]; i != -1; i = ne[i]) {
                if (ch[e[i]] == -1 && f[i]) {
                    ch[q[++tail] = e[i]] = ch[t] + 1;
                }
            }
        }
        return ch[T] != -1;
    }
    int zeng(int a, int b) {
        if (a == T)return b;
        int r = 0;
        for (int i = h[a]; i != -1; i = ne[i]) {
            if (ch[a] + 1 == ch[e[i]] && f[i]) {
                int t = zeng(e[i], min(b - r, f[i]));
                if (t > 0)
                {
                    // 可找路径。
                    nex[a >> 1] = (e[i] >> 1);
                }
                f[i] -= t; r += t; f[i ^ 1] += t;
            }
        }
        if (!r)ch[a] = -1;
        return r;
    }
    int dinic() {
        int r = 0, t = 0;
        while (tell()) {
            while (t = zeng(S, INF)) {
                r += t;
            }
        }
        return r;
    }
    void set_S_T(int s, int t)
    {
        S = s;
        T = t;
    }
    void init()
    {
        memset(h, -1, sizeof(h));
        memset(nex, -1, sizeof(nex));
    }
    int n;
    int w[1000];
    bool vis[maxn];
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        gbtb;
        init();
        S = 0;
        T = 1e4 + 10;
        cin >> n;
        int now = 0;
        int num = 0;
        while (now <= n)
        {
            ++num;
            add(S, num << 1, 1);
            add((num << 1) | 1, T, 1);
            for (int i = sqrt(num) + 1; i * i < (num << 1); ++i)
            {
                add((i * i - num) << 1, (num << 1) | 1, 1);
            }
            int s = dinic();
            if (!s)
            {
                w[++now] = num;
            }
        }
        cout << num - 1 << endl;
        int k;
        repd(i, 1, n)
        {
            if (!vis[w[i]])
            {
                k = w[i];
                cout << k;
                vis[k] = 1;
                while (nex[k] != -1 && nex[k] != (T) >> 1 )
                {
                    k=nex[k];
                    vis[k]=1;
                    cout<<" "<<k;
                }
                cout<<endl;
            }
        }
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
    
    
    
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    将jar包安装到本地repository中,---以greenplum.jar举例
    推荐系统学习起步
    代理模式详解:静态代理、JDK动态代理与Cglib动态代理
    MyBatis(四):自定义持久层框架优化
    MyBatis(二):自定义持久层框架思路分析
    MyBatis(一):JDBC使用存在的问题
    PHP编程趣事:能喝几瓶啤酒?
    Linux下的两个经典宏定义
    C/C++中常用的字符串处理函数和内存字符串函数
    设计模式之适配器模式(Adapter Pattern)C++实现
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/11632802.html
Copyright © 2011-2022 走看看