codeforces219D(树形dp)

src:https://vjudge.net/problem/CodeForces-219D

两次dfs的特点,状态的转移要用到父节点的状态,所以分支节点在第二次dfs中才能用到父节点,而根节点在第一次dfs中就算出dp值了,因为它没有父节点,所以它的值在第二次dfs中传下去!!!

树形dp一般解决的树上的最优解问题,第一个下标一般指处在的结点位置,接下来的下标一般是消耗的代价,或是依赖的什么个其他节点!!!

#include <iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<functional>
#include<utility>
#include<string>
#include<string.h>
#include<vector>
#include<iomanip>
#include<stack>
using namespace std;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
const int inf=99999999;

int n,dp[200005],mi,cnt,head[200005];
int k[200005],kcnt;
struct node
{
    int to,v,ne;
}edge[400010];

void init()
{
    cnt=0;kcnt=0;
    memset(dp,0,sizeof(dp));
    mi=inf;
    memset(head,-1,sizeof(head));
}
void add_edge(int a,int b,int v){edge[cnt].to=b;edge[cnt].v=v;edge[cnt].ne=head[a];head[a]=cnt++;}
void dfs(int rt,int u,int fa,int dis)
{
    dp[rt]+=dis;
    for(int i=head[u];i!=-1;i=edge[i].ne){
        int v=edge[i].to;
        if(v==fa)continue;
        dfs(rt,v,u,edge[i].v);
    }
}
void dfs1(int u,int fa)
{
    for(int i=head[u];i!=-1;i=edge[i].ne){
        int v=edge[i].to;
        if(v==fa)continue;
        dfs1(v,u);
        dp[u]+=(dp[v]+edge[i].v);
    }
}
void dfs2(int u,int fa)
{
    for(int i=head[u];i!=-1;i=edge[i].ne){
        int v=edge[i].to;
        if(v==fa)continue;
        dp[v]+=(dp[u]-dp[v]-edge[i].v+edge[i^1].v);//灵活运用异或求反向边(已经add了的,而且cnt从0开始~)
        dfs2(v,u);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n){
        int a,b;
        init();
        for(int i=1;i<n;i++){cin>>a>>b;add_edge(a,b,0);add_edge(b,a,1);}
        //FOR(i,1,n){dfs(i,i,-1,0);}
        //用dfs求路程和的复杂度O(n2)超时!!!
        dfs1(1,-1);dfs2(1,-1); //树形dp O(2n)~~~
        //FOR(i,1,n)cout<<dp[i]<<' ';cout<<endl;//
        FOR(i,1,n){
            if(dp[i]<mi){
                cnt=0;
                mi=dp[i];
                k[cnt++]=i;
            }
            else if(dp[i]==mi){k[cnt++]=i;}
        }
        cout<<mi<<endl;
        cout<<k[0];
        FOR(i,1,cnt-1)cout<<' '<<k[i];
        cout<<endl;
    }
    return 0;
}

 

posted @ 2018-05-14 21:39  WindFreedom  阅读(487)  评论(0)    收藏  举报