zoukankan      html  css  js  c++  java
  • [题解] PowerOJ 1739 魔术球问题 (最大流)

    - 传送门 -

     https://www.oj.swust.edu.cn/problem/show/1739

    #  1739: 魔术球问题 SPJ

    Time Limit: 1000 MS Memory Limit: 65536 KB
    Total Submit: 422 Accepted: 184 Page View: 1330

    Description

    假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。 (1)每次只能在某根柱子的最上面放球。 (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。 试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可 放11 个球。 编程任务: 对于给定的n,计算在n根柱子上最多能放多少个球。

    Input

    由文件input.txt提供输入数据。文件第1 行有1个正整数n(n<=55),表示柱子数。

    Output

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

    4

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

    Source

    线性规划与网络流24题

     

    - 思路 -

     若 i < j 且 i + j 为完全平方数, 则从起点 i 向终点 j 连一条边, 这个问题和最小路径覆盖问题是一样的.
     但是起点终点要怎么分别表示呢, 球的个数是未知的, 我先写了个暴搜搜索 n = 55 的情况, 大概在1300,1400的样子, 于是开了2000, 起点为 x, 终点为 2000 + x.
     输出方案真的是卡成狗哦!
     
     细节见代码.
     

    - 代码 -

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
     
    const int N = 4000 + 5;
    const int M = 1e6;
    const int TMP = 2000;
    const int inf = 0x3f3f3f3f;
     
    int ANS[N<<1];
    int NXT[M], TO[M], FRM[M];
    int V[M], HD[N], GO[N];
    int CUR[N], DIS[N], VIS[N];
    int n, m, sz, cnt, ans, ss, tt;
    queue<int> q;
     
    void add(int x, int y) {
        TO[sz] = y; NXT[sz] = HD[x]; HD[x] = sz; FRM[sz] = x; V[sz++] = 1;
        TO[sz] = x; NXT[sz] = HD[y]; HD[y] = sz; FRM[sz] = y; V[sz++] = 0;
    }
     
    void init(int x) {
        for (int i = 0; i < sz; ++i)
            V[i] = (i%2) ^ 1;
        add(ss, x);
        add(x + TMP, tt);
        for (int i = 1; i < x; ++i) {
            if (sqrt(i+x) - int(sqrt(i+x)) > 0) continue;
            else add(i, x + TMP);
        }
    }
     
    bool bfs() {
        memset(DIS, -1, sizeof (DIS));
        DIS[ss] = 0;
        q.push(ss);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = HD[u]; i != -1; i = NXT[i]) {
                int v = TO[i];
                if (DIS[v] < 0 && V[i]) {
                    DIS[v] = DIS[u] + 1;
                    q.push(v);
                }
            }
        }
        return DIS[tt] > 0;
    }
     
    int dfs(int x, int a) {
        if (x == tt) return a;
        int flow = 0, f;
        for (int& i = CUR[x]; i != -1; i = NXT[i]) {
            if (V[i] && DIS[TO[i]] == DIS[x] + 1)
                if (f = dfs(TO[i], min(a, V[i]))) {
                    V[i] -= f;
                    V[i^1] += f;
                    flow += f;
                    a -= f;
                    if (a == 0) break;
                }
        }
        return flow;
    }
     
    int dinic(int x) {
        int flow = 0;
        while (bfs()) {
            memcpy(CUR, HD, sizeof (HD));
            flow += dfs(ss, inf);
        }
        return (x - flow);
    }
     
    void print(int x) {
        for (int i = 0; i < sz; ++i) {
            if (V[i] == 0 && TO[i] > FRM[i] && FRM[i] != ss && FRM[i] != tt
                    && TO[i] != ss && TO[i] != tt)
            GO[FRM[i]] = TO[i] - TMP;
        }
        memset(VIS, 0, sizeof (VIS));
        int i = 1, j;
        cnt = 0;
        while (i <= x) {
            if (VIS[i]) {
                i++;
                continue;
            }
            ANS[++cnt] = i;
            VIS[i] = 1;
            j = i;
            while (GO[j]) {
                j = GO[j];
                VIS[j] = 1;
                ANS[++cnt] = j;
            }
            ANS[++cnt] = -1;
        }
    }
     
    int main() {
        scanf("%d", &n);
        ss = 0, tt = 4000;
        memset(HD, -1, sizeof (HD));
        for (int i = 1; ; ++i) {
            init(i);
            int tp = dinic(i);
            if (tp > n) {
                printf("%d
    ", i - 1);
                for (int j = 1; j <= cnt; ++j) {
                    if (ANS[j] == -1) printf("
    ");
                    else printf("%d ", ANS[j]);
                }
                break;
            }
            if (tp == n) print(i); //开始记录方案
        }
        return 0;
    }
    
  • 相关阅读:
    第21周六
    第21周五
    第21周四
    第21周三
    C/C++中各种类型int、long、double、char表示范围(最大最小值)
    插入排序
    面向对象的5个基本设计原则
    红黑树
    Cocos2d-x学习笔记(六) 定时器Schedule的简单应用
    SNMP协议具体解释
  • 原文地址:https://www.cnblogs.com/Anding-16/p/7412068.html
Copyright © 2011-2022 走看看