zoukankan      html  css  js  c++  java
  • 题解 洛谷 P4189 【[CTSC2010]星际旅行】

    一个比较直接的想法就是对每个点进行拆点,拆成入点和出点,限制放在入点和出点相连的边上,然后跑最大费用最大流即可。

    但是这样复杂度无法接受,所以考虑模拟费用流来解决本题。

    发现 (H) 都大于等于该节点的度数,所以从根节点出发,一定可以到达所有节点。

    先考虑以根节点为起点和终点的答案,首先可以遍历整棵树后回到根节点,每条边的两个端点的 (H) 都减一,答案加二。然后继续考虑每条边的贡献,若其两个端点在遍历后 (H) 不为 (0),则可以反复走这条边,直到其中一个端点的 (H)(0)

    得出根节点的答案后,考虑如何推出其他点的答案。设当前节点为 (x),当前考虑的儿子为 (y)。若 (H_x) 不为 (0),则可以直接从 (x) 走到 (y),使答案加一。若 (H_x)(0),那么从 (y)(x) 后从 (x) 就无法到达 (y),所以进行反悔退流,将原先 (y)(x) 的一个流退掉,如果此时 (y) 存在一个儿子的 (H) 不为 (0),那么其就可以反复走和这个儿子相连的边,使答案加一,若没有,则答案减一。

    同时还要注意在 (dfs) 时需要回溯。

    #include<bits/stdc++.h>
    #define maxn 100010
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,tot;
    int v[maxn],ans[maxn],son[maxn];
    struct edge
    {
        int to,nxt;
    }e[maxn];
    int head[maxn],edge_cnt;
    void add(int from,int to)
    {
        e[++edge_cnt]=(edge){to,head[from]};
        head[from]=edge_cnt;
    }
    void dfs_pre(int x,int fa)
    {
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to,val;
            if(y==fa) continue;
            dfs_pre(y,x),val=min(v[x],v[y]);
            v[x]-=val,v[y]-=val,tot+=val*2;
            if(v[y]) son[x]=y;
        }
    }
    void dfs_ans(int x,int fa)
    {
        ans[x]=tot;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to,type;
            if(y==fa) continue;
            if(v[x]) v[x]--,tot++,type=1;
            else if(son[y]) v[son[y]]--,tot++,type=2;
            else v[y]++,tot--,type=3;
            dfs_ans(y,x);
            if(type==1) v[x]++,tot--;
            if(type==2) v[son[y]]++,tot--;
            if(type==3) v[y]--,tot++;
        }
    }
    int main()
    {
        read(n);
        for(int i=1;i<=n;++i) read(v[i]);
        for(int i=1;i<n;++i)
        {
            int x,y;
            read(x),read(y),x++,y++;
            add(x,y),add(y,x),v[x]--,v[y]--,tot+=2;
        }
        dfs_pre(1,0),dfs_ans(1,0);
        for(int i=1;i<=n;++i) printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    学习使用apt(三)
    2005 男人感悟100(转自MOP)
    学习使用apt
    学习使用apt(四)
    编译glib1.2.20r5出错./libtool: line 297
    poj1004的java实现
    猜算式
    基于爬山算法求解TSP问题(JAVA)
    mysql数据库的简单语句的介绍(1)
    NYOJ42 一笔画问题
  • 原文地址:https://www.cnblogs.com/lhm-/p/13353381.html
Copyright © 2011-2022 走看看