• luogu2765 魔术球问题 网络流


    题目大意:

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

    关键字:网络流 拆点 上下界 二分查找

    网络流:

    想象拿柱子去串球,一个柱子就相当于一个流量为1的流。

    拆点建图:

    为保证每个球都能串在一个柱子上,将每个球拆成一条边,要求边内流量必须为1(即该边上下界都为1)。

    若两球数字和为完全平方数,则将一球边的to节点连另一球边的from节点(注意球是按顺序放的,因此若a数字小于b数字,要么a连b,要么b连a,不能双向都连)。

    为了满足网络流形式,“s”点向每个球边from点连边,每个球边to点向t点连边,容量为1。

    因为柱子数量有限,因此将s点向“s”点连容量为柱子数量的边。

    上下界:

    根据上下界网络流处理办法,S点连每个球边to节点,每个球边from节点连T节点。之前的球边容量变为0,删去。t点向s点连容量∞边,即t,s点合并(合并点在代码中为orgT,"s"点为orgS)。

    枚举:二分枚举球的数量直到得出答案。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <cassert>
    using namespace std;
    
    //#define test
    #define INF 0x3f3f3f3f
    #define P(x) x*2+3
    #define Q(x) x*2+4
    #define arcP(x) (x-3)/2
    #define arcQ(x) (x-4)/2
    const int MAX_BALL = 2510, MAX_NODE = MAX_BALL * 3, MAX_EDGE = 50000, TOT_BALL = 2500;
    
    struct Dinic
    {
        struct Edge;
        struct Node;
    
        struct Node
        {
            int Id, Level;
            Edge* Head;
            Edge *DfsFrom;
            bool Deled;
            Node() { Deled = false; }
        };
    
        struct Edge
        {
            int Cap, OrgCap;
            Node *From, *To;
            Edge *Next, *Rev;
            Edge(int cap, Node *from, Node *to, Edge *next) :Cap(cap), OrgCap(cap), From(from), To(to), Next(next) {}
        };
    
        Node _nodes[MAX_NODE];
        Edge *_edges[MAX_EDGE];
        int _vCount, _eCount;
        Node *StartNode, *TargetNode;
    
        void Init(int sId, int tId, int vCount)
        {
            memset(_nodes, 0, sizeof(_nodes));
            memset(_edges, 0, sizeof(_edges));
            _eCount = 0;
            _vCount = vCount;
            StartNode = sId + _nodes;
            TargetNode = tId + _nodes;
        }
    
        void Reuse(Node *cur)
        {
            cur->Deled = false;
            for (Edge *e = cur->Head; e; e = e->Next)
            {
                if (!e->To->Deled)
                {
                    e->Cap = e->OrgCap;
                    e->Rev->Cap = e->Rev->OrgCap;
                }
            }
        }
    
        void ReuseById(int id)
        {
            Reuse(id + _nodes);
        }
    
        Edge* AddEdge(Node *from, Node *to, int eCap)
        {
            assert(from != to);
            Edge *cur = _edges[++_eCount] = new Edge(eCap, from, to, from->Head);
            cur->From->Head = cur;
            return cur;
        }
    
        void DeleteNode(Node *cur)
        {
            cur->Deled = true;
            for (Edge *e = cur->Head; e; e = e->Next)
            {
                e->Cap = e->Rev->Cap = 0;
            }
        }
    
        void DeleteById(int id)
        {
            DeleteNode(id + _nodes);
        }
    
        void Build(int uId, int vId, int eCap)
        {
            Node *u = uId + _nodes, *v = vId + _nodes;
            u->Id = uId;
            v->Id = vId;
            Edge *edge1 = AddEdge(u, v, eCap), *edge2 = AddEdge(v, u, 0);
            edge1->Rev = edge2;
            edge2->Rev = edge1;
        }
    
        struct NodeQueue
        {
            Node *q[MAX_NODE];
            int head, tail;
            void clear() { head = tail = 0; }
            void push(Node *v) { q[tail++] = v; }
            Node* front() { return q[head]; }
            void pop() { head++; }
            bool empty() { return head == tail; }
        };
    
        bool Bfs()//常规,从源点构造
        {
            for (int i = 1; i <= _vCount; i++)
                _nodes[i].Level = 0;
            static NodeQueue q;
            q.clear();
            StartNode->Level = 1;
            q.push(StartNode);
            while (!q.empty())
            {
                Node *u = q.front();
                q.pop();
                for (Edge *e = u->Head; e; e = e->Next)
                {
                    assert(e->Cap >= 0);
                    if (!e->To->Level && e->Cap)
                    {
                        e->To->Level = u->Level + 1;
                        q.push(e->To);
                    }
                }
            }
            return TargetNode->Level;//遗忘点
        }
    
        int Dfs(Node *cur, int limit)
        {
            if (cur == TargetNode)
                return limit;
            if (limit == 0)
                return 0;
            int curTake = 0;
            for (Edge *e = cur->DfsFrom; e; cur->DfsFrom = e = e->Next)
            {
                if (e->To->Level == cur->Level + 1 && e->Cap)
                {
                    int nextTake = Dfs(e->To, min(limit - curTake, e->Cap));
                    e->Cap -= nextTake;
                    e->Rev->Cap += nextTake;
                    curTake += nextTake;
                }
                if (limit - curTake == 0)
                    break;
                //assert(e->Cap == 0);
            }
            return curTake;
        }
    
    
        int Proceed()
        {
            int ans = 0;
            while (Bfs())
            {
                for (int i = 0; i <= _vCount; i++)
                    _nodes[i].DfsFrom = _nodes[i].Head;
                ans += Dfs(StartNode, INF);
    #ifdef test
                printf("ans=%d
    ", ans);
    #endif
            }
            //printf("ans %d
    ", ans);
            return ans;
        }
    }g;
    Dinic::Edge *ts;
    
    bool IsSquare(int x)
    {
        int a = floor(sqrt(x) + 0.5);
        return a*a == x;
    }
    
    bool Judge(int ballCnt)
    {
        //printf("ballCnt %d
    ", ballCnt);
        g._vCount = ballCnt * 2 + 4;
        ts->Cap = ts->OrgCap;
        ts->Rev->Cap = ts->Rev->OrgCap;
        for (int ball = ballCnt + 1; ball <= TOT_BALL; ball++)
        {
            g.DeleteById(P(ball));
            g.DeleteById(Q(ball));
        }
        for (int ball = 1; ball <= ballCnt; ball++)
        {
            g.ReuseById(P(ball));
            g.ReuseById(Q(ball));
        }
        return g.Proceed() == ballCnt;
    }
    
    int Bsearch(int maxL, int maxR)
    {
        int l = maxL, r = maxR, ans = -1;
        while (l <= r)
        {
            int mid = (l + r) / 2;
            if (Judge(mid))
                l = (ans = mid) + 1;
            else
                r = mid - 1;
        }
        return ans;
    }
    
    void InitBuild(int totPole)
    {
        int sId = 1, tId = 2, orgS = 3, orgT = 4;
        g.Init(sId, tId, 4);
        g.Build(orgT, orgS, totPole);
        ts = g._edges[g._eCount - 1];
        for (int ballNum = 1; ballNum <= TOT_BALL; ballNum++)
        {
            g._vCount += 2;
            g.Build(sId, Q(ballNum), 1);
            g.Build(P(ballNum), tId, 1);
            g.Build(orgS, P(ballNum), 1);
            g.Build(Q(ballNum), orgT, 1);
            for (int i = 1; i < ballNum; i++)
                if (IsSquare(i + ballNum))
                    g.Build(Q(i), P(ballNum), 1);
        }
    }
    
    void Print(int ballNum)
    {
        static bool Vis[MAX_BALL];
        for (int i = 1; i <= ballNum; i++)
        {
            if (Vis[i])
                continue;
            Dinic::Node *p = P(i) + g._nodes, *q = Q(i) + g._nodes;
            bool stop = false;
            while (!stop)
            {
                Vis[arcP(p->Id)] = true;
                printf("%d ", arcP(p->Id));
                stop = true;
                for (Dinic::Edge *e = q->Head; e; e = e->Next)
                {
                    if (arcP(e->To->Id) <= ballNum)
                        //printf("print %d' - %d cap %d
    ", arcQ(q->Id), arcP(e->To->Id), e->Cap);
                        if (!e->Cap && 1 <= arcP(e->To->Id) && arcP(e->To->Id) <= ballNum && !Vis[arcP(e->To->Id)] && !e->To->Deled)
                        {
                            stop = false;
                            p = e->To;
                            q = Q(arcP(p->Id)) + g._nodes;
                            break;
                        }
                }
            }
            printf("
    ");
        }
    }
    
    int main()
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        int totPole;
        scanf("%d", &totPole);
        InitBuild(totPole);
        int ballNum = Bsearch(1, TOT_BALL);
        printf("%d
    ", ballNum);
        Judge(ballNum);
        Print(ballNum);
        return 0;
    }
  • 相关阅读:
    移动端hybrid开发复盘
    node/webpack 调试 loader 等技巧
    javascript(js)小数精度丢失的解决方案
    必经之路--买房之后需要走的流程--针对 组合贷款方式
    canvas 画半圆的两种方式
    svg path 画圆
    1.快速排序
    7.桥接设计模式
    6.适配器设计模式
    5.策略设计模式
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8433316.html
Copyright © 2020-2023  润新知