Choosing Capital for Treeland -樹形DP
阿新 • • 發佈:2018-12-18
- 題意:給出具有N個節點的樹,現在給出N-1條有向邊,問我們最少改變多少條邊的方向,使得我們能夠從一個點。
- 到達其餘所有的點。並且輸出各個點的編號。
- 思路:第一遍dfs,dp裡面存的是它到所有子樹節點的需要翻轉的次數,第二次更新ans存的是它到全體的節點的翻轉次數
- ans[v]+=ans[u]-dp[v]-edge[i].flag+!edge[i].flag;
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 200050 int dp[maxn],s,t; int head[maxn],n; int tot,ans[maxn]; struct node { int v,flag,to; } edge[maxn*2]; void add(int u,int v) { edge[++tot].v=v; edge[tot].to=head[u]; edge[tot].flag=0; head[u]=tot; edge[++tot].v=u; edge[tot].to=head[v]; edge[tot].flag=1; head[v]=tot; } void dfs1(int u,int pre) { for(int i=head[u]; i!=-1; i=edge[i].to) { int v=edge[i].v; if(v==pre)continue; dfs1(v,u); dp[u]+=dp[v]+edge[i].flag; } } void dfs2(int u,int pre) { ans[u]+=dp[u]; for(int i=head[u]; i!=-1; i=edge[i].to) { int v=edge[i].v; if(v==pre)continue; ans[v]+=ans[u]-dp[v]-edge[i].flag+!edge[i].flag; dfs2(v,u); } } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1; i<n; i++) { scanf("%d%d",&s,&t); add(s,t); } dfs1(1,-1); dfs2(1,-1); vector<int>qq; int sum=inf; for(int i=1; i<=n; i++) if(ans[i]<sum) sum=ans[i]; for(int i=1; i<=n; i++) if(ans[i]==sum)qq.push_back(i); sort(qq.begin(),qq.end()); int len=qq.size(); printf("%d\n",sum); for(int i=0; i<len; i++) if(i==len-1) printf("%d\n",qq[i]); else printf("%d ",qq[i]); return 0; }