CodeForces

题意:有向树,要求找最小的需要修改边的方向的数目,使得该点能到达树上每一个点,并求出所有最小数目的点

解法:树形dp,先从1开始dfs一遍(dp【u】是以u为根 的子树需要修改的边数)转移方程如果是u->x,dp【x】+=dp【u】+1,否则dp【x】+=dp【u】,再把dp【i】的意义改成以u为根的需要修改的边数,重新dfs一遍,转移方程if:u->x,dp【x】=dp【u】+1,else:dp【x】=dp【u】-1

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

using namespace std;
using namespace __gnu_cxx;

const double g=10.0,eps=1e-7;
const int N=200000+10,maxn=60000+10,inf=0x3f3f3f3f;

vector<int>v[N];
map<int,int>m[N];
int dp[N];
void dfs(int u,int f)
{
    for(int i=0;i<v[u].size();i++)
    {
        int x=v[u][i];
        if(x==f)continue;
        dfs(x,u);
        if(m[u][x])dp[u]+=dp[x];
        else dp[u]+=dp[x]+1;
    }
}
void dfs1(int u,int f)
{
    for(int i=0;i<v[u].size();i++)
    {
        int x=v[u][i];
        if(x==f)continue;
        if(m[u][x])dp[x]=dp[u]+1;
        else dp[x]=dp[u]-1;
        dfs1(x,u);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int a,b;
        cin>>a>>b;
        v[a].pb(b);
        v[b].pb(a);
        m[a][b]=1;
    }
    dfs(1,-1);
    dfs1(1,-1);
    int minn=300000;
    for(int i=1;i<=n;i++)minn=min(minn,dp[i]);
    cout<<minn<<endl;
    for(int i=1;i<=n;i++)
        if(dp[i]==minn)
            cout<<i<<" ";
    return 0;
}
/************

************/
View Code
原文地址:https://www.cnblogs.com/acjiumeng/p/7783934.html