zoukankan      html  css  js  c++  java
  • 【题解】【CTST2010】星际旅行

    看到这道题第一眼是什么?

    网络流!exciting!

    大佬们以光速复制敲好板子,用3毫秒想出了如何建模,打好程序,看眼数据范围……

    笑容渐渐消失.jpg

    什么,还有我预流推进解决不了的卡常网络流?

    还真搞不定

    再仔细看一眼:N个星球,N-1条双向时空隧道,任意两点联通

    ——这是树!

    树上网络流不行,那么……还有什么算法可以解决这类问题……

    ——树上DP!

    好了怎么DP也是一个问题啊

    先看一句话:

    每个星球的H_iHi大于等于与该星球直接相连的星球数(即度数)。

    什么鬼?为什么会有这种毒瘤玩意儿?

    其实ta给我们提供了一个很关键的信息:

    由于有Hi>=i的度数,那么可以想象在最坏情况下(比如所有Hi=i的度数),答案至少是根节点走过所有点之后回到根节点,然后去掉一个点i到根节点的那些路径。

    ——来自https://blog.csdn.net/lych_cys/article/details/51062609

    那么感性一下,答案大概就是根节点回到根节点的最大流量,使得没有一条边e(u,v),u和v的可出发次数都>0。

    分三种情况讨论:

    1. 还可以从x处出发,总流量++,cnt[x]--
    2. y而儿子中存在一个点p的可出发次数>0,那么可以让y->x的流量-1,然后y->p流量+1,p->y流量+1,p的可出发次数-1;
    3. 否则没有办法到达y,那么只能让y->x的边退流,同时y的可出发次数+1。

    ——仍然来自https://blog.csdn.net/lych_cys/article/details/51062609

    那么……

    这就很显然了,代码就不防了(被泼硫酸

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    /*
    inline void read(int &x)
    {
        x=0;
        int f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')
            {
                f=-1;
            }
            ch=getchar();
        }
        while(ch<='9'&&ch>='0')
        {
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    */
    struct note
    {
        int next;
        int t;
    };
    
    note e[200010];
    int head[50010],ind[50010];
    int n;
    int cnt;
    int flag[50010],ans[50010],g[50010];
    int flow;
    
    inline void add(int x,int y)
    {
        e[++cnt].t=y;
        e[cnt].next=head[x];
        head[x]=cnt;
        ind[y]--;
    }
    
    void dfs(int x,int fa)
    {
        for(int i=head[x];i+1;i=e[i].next)
        {
            int p=e[i].t;
            if(p==fa)
            {
                continue;
            }
            dfs(p,x);
            int val=min(ind[p],ind[x]);
            ind[x]-=val;
            ind[p]-=val;
            flow+=val<<1;
            if(ind[p])
            {
                g[x]=p;
            }
        }
    }
    
    void solve(int x,int fa)
    {
        ans[x]=flow;
        for(int i=head[x];i+1;i=e[i].next)
        {
            int p=e[i].t;
            if(p==fa)
            {
                continue;
            }
            if(ind[x])
            {
                ind[x]--;
                flow++;
                flag[x]=0;
            }
            else if(g[p])
            {
                ind[g[p]]--;
                flow++;
                flag[x]=1;
            }
            else
            {
                ind[p]++;
                flow--;
                flag[x]=2;
            }
            solve(p,x);
            if(!flag[x])
            {
                ind[x]++;
                flow--;
            }
            else if(flag[x]==1)
            {
                ind[g[p]]++;
                flow--;
            }
            else
            {
                ind[p]--;
                flow++;
            }
        }
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&ind[i]);
        }
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            x++;
            y++;
            add(x,y);
            add(y,x);
        }
        flow=(n-1)<<1;
        dfs(1,-1);
        solve(1,-1);
        for(int i=1;i<=n;i++)
        {
            printf("%d
    ",ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    Java第九次作业
    Java第八次作业
    Java第七次作业
    Java第六次作业
    Java第五次作业
    Java第四次作业
    Java第三次作业
    Java第二次作业
    Java第一次作业
    高级工程师和初级工程师之间的一道坎
  • 原文地址:https://www.cnblogs.com/tt66ea-blog/p/10540628.html
Copyright © 2011-2022 走看看