상자 트리 (DP)

머리말

DP 자신의 나무가 너무 많은 음식, 우리는 참여에 초점을 맞추어야한다

219D는 Treeland에 대한 자본 선택

마침내 그는 자신을 변화 DP의 루트가 아닌 암을했다

주문 \ (F [U] \) 로 표시 \ (U \) 루트를 들어, 측면의 수가 총 서브 트리가 교환 (최대 [U] \) \ 로 표시 \ (U는 \) 루트 서브 트리의 외측은 측면의 총 수는 교환이 필요합니다.

Dfs1 수득 \ (F [U] \) , 거기 :

\ [F [U] = \ sum_ {v∈son [U]} F [V] + (에지 [U-> V] == 1) \]

에지 [U-> V는 이러한 에지의 U-> V 방향을 나타내고 있지 U-> V는

DFS2 취득 ([V] \까지) \ ( 참고, 포인트 V에서 U U 아들을 추구하는 지점입니다 포함과 배제에 대해이)있다 :

\ [UP [V] = f는 [U]를 -f [V]까지 + [U] + (+ 1 / -1) \]

(+ 1 / -1) (1) [U -> V]는 동일한 에지를 표시하고, 다음 하나 개 이상의 측 방향 전환이있는 쪽이 과충전 때문 -1 필요가 없다

암호

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 2e5+7;
int n,cnt;
int head[N],f[N],up[N];
struct Edge {
    int next,to,flag;
}edge[N<<1];
inline void add(int u,int v,int flag) {
    edge[++cnt] = (Edge)<%head[u],v,flag%>;
    head[u] = cnt;
}
void Dfs1(int u,int fa) {
    for(int i=head[u];i;i=edge[i].next) {
        int v = edge[i].to;
        if(v != fa) {
            Dfs1(v,u);
            f[u] += f[v] + (edge[i].flag==0); //·´±ß 
        }
    }
}
void Dfs2(int u,int fa) {
    for(int i=head[u];i;i=edge[i].next) {
        int v = edge[i].to;
        if(v != fa) {
            up[v] = f[u] - f[v] + up[u];
            if(edge[i].flag == 1) up[v]++;
            else up[v]--;
            Dfs2(v,u);
        }
    }
}
int main()
{
    n = read();
    for(int i=1,u,v;i<=n-1;++i) {
        u = read(), v = read();
        add(u,v,1), add(v,u,0);
    }
    Dfs1(1,0);
    Dfs2(1,0);
    int ans = INF;
    for(int i=1;i<=n;++i)
        ans = min(ans,f[i]+up[i]);
    printf("%d\n",ans);
    for(int i=1;i<=n;++i)
        if(f[i]+up[i] == ans) printf("%d ",i);
    return 0;
}
/*
4
1 4
2 4
3 4

2
1 2 3 
*/

추천

출처www.cnblogs.com/BaseAI/p/11824204.html