zoukankan      html  css  js  c++  java
  • Codeforces 219D

    http://codeforces.com/problemset/problem/219/D

    题意

    给一颗树但边是单向边,求至少旋转多少条单向边的方向,可以使得树上有一点可以到达树上任意一点,若有多个答案按顺序全部输出。

    分析

    把边的方向化为权值,正向为0,逆向为1。问题转化为找哪些点的在遍历全图后总权值最小。这就是树形DP了,它可以从子树收获价值,也可以从父亲收获。所以dfs两遍。

    定义dp[u][0]为以u为根的的子树全可达的修改次数,随便选定一个点,用子节点信息更新父节点,dp[u][0]+=dp[v][0]+w;

    再定义dp[u][1]为以u为根的整颗树需要修改的次数,根据第一次dp的结果,利用父节点的信息来更新子节点。

    如果fa指向u,那么dp[u][1]=dp[fa][1]-1;如果u指向fa,那么dp[u][1]=dp[fa][1]+1;

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<set>
    #define rep(i,e) for(int i=0;i<(e);i++)
    #define rep1(i,e) for(int i=1;i<=(e);i++)
    #define repx(i,x,e) for(int i=(x);i<=(e);i++)
    #define X first
    #define Y second
    #define PB push_back
    #define MP make_pair
    #define mset(var,val) memset(var,val,sizeof(var))
    #define scd(a) scanf("%d",&a)
    #define scdd(a,b) scanf("%d%d",&a,&b)
    #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
    #define pd(a) printf("%d
    ",a)
    #define scl(a) scanf("%lld",&a)
    #define scll(a,b) scanf("%lld%lld",&a,&b)
    #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
    #define IOS ios::sync_with_stdio(false);cin.tie(0)
    
    using namespace std;
    typedef long long ll;
    template <class T>
    void test(T a){cout<<a<<endl;}
    template <class T,class T2>
    void test(T a,T2 b){cout<<a<<" "<<b<<endl;}
    template <class T,class T2,class T3>
    void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;}
    const int N = 1e6+10;
    //const int MAXN = 210;
    const int inf = 0x3f3f3f3f;
    const ll INF = 0x3f3f3f3f3f3f3f3fll;
    const ll mod = 200907;
    int T;
    void testcase(){
        printf("Case #%d: ",++T);
    }
    const int MAXN = 2e5+5;
    const int MAXM = 30;
    
    struct node{
        int to,w,nxt;
    }edge[MAXN<<1];
    
    int cnt,head[MAXN];
    int dp[MAXN][2];
    
    void init(){
        cnt=0;
        mset(head,-1);
    }
    
    void addEdge(int u,int v,int w){
        edge[cnt].to=v;
        edge[cnt].w=w;
        edge[cnt].nxt=head[u];
        head[u]=cnt++;
    }
    
    void sear(int u,int pa){
        dp[u][0]=0;
        for(int i=head[u];~i;i=edge[i].nxt){
            int v=edge[i].to;
            if(v!=pa){
                sear(v,u);
                dp[u][0]+=(dp[v][0]+edge[i].w);
            }
        }
    }
    void dfs(int u,int pa,int x){
        if(u==pa){
            dp[u][1]=dp[u][0];
        }else{
            if(x==0) dp[u][1]=dp[pa][1]+1;//pa->u
            else dp[u][1]=dp[pa][1]-1;//u->pa
        }
        for(int i=head[u];~i;i=edge[i].nxt){
            int v=edge[i].to;
            if(v!=pa){
                dfs(v,u,edge[i].w);
            }
        }
    }
    
    int main() {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif // LOCAL
        int n;
        scd(n);
        int u,v;
        init();
        for(int i=1;i<n;i++){
            scdd(u,v);
            addEdge(u,v,0);
            addEdge(v,u,1);
        }
        sear(1,-1);
    //    for(int i=1;i<=n;i++) printf("%d ",dp[i][0]);puts("");
        dfs(1,1,0);
        int ans=inf;
        for(int i=1;i<=n;i++) ans=min(ans,dp[i][1]);
        cout<<ans<<endl;
        for(int i=1;i<=n;i++){
            if(ans==dp[i][1]){
                printf("%d ",i);
            }
        }
        return 0;
    }
  • 相关阅读:
    【luogu4719】动态DP模板 [动态DP]
    【2019.9.22】
    [JSOI2010]连通数[tarjan缩点]
    【2019.9.16】Za
    【2019.9.18】Za
    [USACO14OPEN]GPS的决斗Dueling GPS's [最短路]
    【CF891C】Envy [最小生成树]
    【2019.9.17】Za
    【2019.9.17】
    【luogu3403】跳楼机 [同余最短路]
  • 原文地址:https://www.cnblogs.com/fht-litost/p/9292806.html
Copyright © 2011-2022 走看看