Codeforces 219D - Choosing Capital for Treeland(树形dp)

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\n",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;
}

猜你喜欢

转载自www.cnblogs.com/fht-litost/p/9292806.html
今日推荐