树形dp 219D Choosing Capital for Treeland

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

题意:

可以这么理解为—— 一些城市的道路之间是有向边,如果沿着路的方向来走花费的价值为 0,如果逆向行走花费的价值为 1,选择一些点为首都,使其到其他点所花费的价值最小

思路:

树形dp

运用两次深搜,第一次深搜求出点i到以其自身为根节点的子树上其他点总共需要花费的价值,dp[ i ] 记录。

第二次深搜,根据第一次dp的结果,利用父节点的信息来更新子节点,求出点i到整个图中其他任意点所花费的价值,dp[ i ] 记录。

如果root指向son   dp[son] = dp[root] + 1;

如果son指向root   dp[root] = dp[son] + 1;

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int N =2e5+5;
struct node
{
    int v,w;
};
vector<node> g[N];
bool flag[N];
int dp[N];
queue<int> q;
void dfs(int root)
{
    flag[root] = true;
    int i;
    for(i= 0; i < (int)g[root].size(); i++)
    {
        int son = g[root][i].v;
        if(flag[son]) continue;
        dfs(son);
        if(g[root][i].w == 0)
        {
            dp[root] += dp[son] + 1;
        }
        else
        {
            dp[root] += dp[son];
        }
    }
}
void DFS(int root)
{
    flag[root] = true ;
    int i;
    for(i = 0; i < (int) g[root].size(); i++)
    {
        int son = g[root][i].v;
        if(flag[son]) continue;
        if(g[root][i].w == 0)
        {
            dp[son] = dp[root] - 1; // 反向
        }
        else
        {
            dp[son] = dp[root] + 1; // 正向
        }
        DFS(son);
    }
}
int main()
{
    int n,i,u,v;
    while(~scanf("%d",&n))
    {
        for(i = 1; i <= n; i++)
        {
            flag[i] = false;
            g[i].clear();
            dp[i] = 0;
        }
        node temp;
        for(i = 1; i < n; i++)
        {
            scanf("%d%d",&u,&v);
            temp.v = v;
            temp.w = 1;
            g[u].push_back(temp);
            temp.v = u;
            temp.w = 0;
            g[v].push_back(temp);
        }
        dfs(1);
        memset(flag,false,sizeof(flag));
        DFS(1);
        while(!q.empty())
        {
            q.pop();
        }
        int Min = N;
        for(i = 1; i <= n; i++)
        {
            if(dp[i] < Min)
            {
                Min = dp[i];
                while(!q.empty())
                {
                    q.pop();
                }
                q.push(i);
                continue;
            }
            if(dp[i] == Min)
            {
                q.push(i);
            }
        }
        printf("%d\n",Min);
        printf("%d",q.front());
        q.pop();
        while(!q.empty())
        {
            printf(" %d",q.front());
            q.pop();
        }
        puts("");
    }
    return 0;
}


你可能感兴趣的:(树形dp 219D Choosing Capital for Treeland)