zoukankan      html  css  js  c++  java
  • 洛谷 P2765 魔术球问题 题解

    作者:岸芷汀兰

    一、题目:

    洛谷原题

    二、思路:

    既然是网络流24题中的一道,那么肯定要用到网络流模型。

    其实大多数OI题都是模型的运用和转化,此题也不例外。

    如果没有做过这道题的同学可以先做一下,再来理解本题可能会容易一些。

    我们会发现如果我们这样建图:

    (forall u < v)如果(u + v)是完全平方数,那么我们就从u向v连一条有向边,那么最终的图G一定是个DAG。

    每一根柱子,记最下面的数为(x),最上面的数为(y),那么这根柱子就对应着图G中的一条从(x)(y)的路径。

    现在把原题改一下,改为给你(m),让你求:要想把(1sim m)的数字摆到柱子上,最小需要几个柱子。那是不是就对应着图G的最小路径覆盖问题?

    那么现在再来考虑本题,本题是给你(n)个柱子,让你求最大的(m),那么我们可以依次增加(m),检查当前的图G的最小路径覆盖是否小于等于(n),如果大于了(n),就立即跳出。

    至于怎样输出答案,与“最小路径覆盖”那道题的输出方法一模一样,在此不再赘述。

    三、代码:

    //好看的代码是理解OI题的基础
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    
    #define LL long long
    #define mem(s, v) memset(s, v, sizeof s)
    
    inline LL read(void) {
        LL x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return f * x;
    }
    
    const int inf = 1e9 + 5;
    const int maxn = 1e5 + 5;
    
    int to[maxn], nxt[maxn], head[30005], tot = 1;
    int cur[maxn];
    
    int n, s, t;
    int w[maxn];
    
    inline void add(int x, int y, int z) {
        to[++tot] = y; nxt[tot] = head[x]; head[x] = tot; w[tot] = z;
        to[++tot] = x; nxt[tot] = head[y]; head[y] = tot;
    }
    
    inline int id(int x, int y) { return x + y * 10000; }//拆点
    
    inline void AddEdge(int x) {
        for (register int i = 1; i < x; ++i) {
            int tmp = i + x;
            if ((int)sqrt(tmp) * (int)sqrt(tmp) == tmp) {
                add(id(i, 0), id(x, 1), 1);
            }
        }
        add(s, id(x, 0), 1); add(id(x, 1), t, 1);
    }//每增加一次m,更新一下图G
    
    int q[maxn], l, r, vis[maxn], h[maxn];
    
    inline bool bfs(void) {
        for (register int i = 1; i <= t; ++i) h[i] = inf, cur[i] = head[i], vis[i] = 0;
        h[s] = 0; l = r = 1; q[r++] = s;
        while (r - l) {
            int u = q[l++]; vis[u] = 0;
            for (register int i = head[u]; i; i = nxt[i]) {
                int v = to[i];
                if (w[i] && h[v] > h[u] + 1) {
                    h[v] = h[u] + 1;
                    if (!vis[v]) q[r++] = v, vis[v] = 1;
                }
            }
        }
        return h[t] < inf;
    }
    
    int dfs(int u, int flow) {
        if (u == t) { return flow; }
        int tmp, used = 0;
        for (register int i = cur[u]; i; i = nxt[i]) {
            int v = to[i]; cur[u] = i;
            if (w[i] && h[v] == h[u] + 1) {
                if (tmp = dfs(v, min(flow - used, w[i]))) {
                    w[i] -= tmp; w[i ^ 1] += tmp;
                    used += tmp;
                    if (used == flow) break;
                }
            }
        }
        return used;
    }
    
    int maxflow;
    
    inline void dinic(void) {
        while (bfs()) {
            maxflow += dfs(s, inf);
        }
    }
    
    int suc[maxn];
    
    inline void print(int x) {//输出“路径”
        while (x) {
            printf("%d ", x);
            vis[x] = 1; 
            x = suc[x];
        }
    }
    
    int main() {
        n = read(); s = id(10000, 1) + 1, t = s + 1;
        int now = 0, cnt = 0;
        while (now <= n) {
            ++cnt; AddEdge(cnt);
            dinic();
            now = max(now, cnt - maxflow);
        }
        printf("%d
    ", cnt - 1);
        for (register int i = 1; i <= cnt - 1; ++i) {
            for (register int j = head[i]; j; j = nxt[j]) {
                int v = to[j];
                if (v != s && v != t) {
                    if (w[j ^ 1]) {
                        suc[i] = v - 10000;
                        break;
                    }
                }
            }
        }
        mem(vis, 0);
        for (register int i = 1; i <= cnt - 1; ++i) {
            if (!vis[i]) print(i), puts("");
        }
        return 0;
    }
    
    
  • 相关阅读:
    洛谷 P2370 P2370 yyy2015c01的U盘
    洛谷 P1214 等差数列
    洛谷 P1483 序列变换
    洛谷 P2032 扫描
    洛谷 P2846 光开关
    洛谷 P2872 道路建设
    Codeforces Round #510 #C Array Product
    Codeforces Round #510 #B
    Codeforces Round #510 #A
    关于各种数字倍数的判断
  • 原文地址:https://www.cnblogs.com/little-aztl/p/12165755.html
Copyright © 2011-2022 走看看