codeforces219D(樹形dp)

src:https://vjudge.net/problem/CodeForces-219Dnode

兩次dfs的特色,狀態的轉移要用到父節點的狀態,因此分支節點在第二次dfs中才能用到父節點,而根節點在第一次dfs中就算出dp值了,由於它沒有父節點,因此它的值在第二次dfs中傳下去!!!ios

樹形dp通常解決的樹上的最優解問題,第一個下標通常指處在的結點位置,接下來的下標通常是消耗的代價,或是依賴的什麼個其餘節點!!!spa

#include <iostream> #include<cstdlib> #include<algorithm> #include<cmath> #include<functional> #include<utility> #include<string> #include<string.h> #include<vector> #include<iomanip> #include<stack>
using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++)
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
const int inf=99999999; int n,dp[200005],mi,cnt,head[200005]; int k[200005],kcnt; struct node { int to,v,ne; }edge[400010]; void init() { cnt=0;kcnt=0; memset(dp,0,sizeof(dp)); mi=inf; memset(head,-1,sizeof(head)); } void add_edge(int a,int b,int v){edge[cnt].to=b;edge[cnt].v=v;edge[cnt].ne=head[a];head[a]=cnt++;} void dfs(int rt,int u,int fa,int dis) { dp[rt]+=dis; for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; if(v==fa)continue; dfs(rt,v,u,edge[i].v); } } void dfs1(int u,int fa) { for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; if(v==fa)continue; dfs1(v,u); dp[u]+=(dp[v]+edge[i].v); } } void dfs2(int u,int fa) { for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; if(v==fa)continue; dp[v]+=(dp[u]-dp[v]-edge[i].v+edge[i^1].v);//靈活運用異或求反向邊(已經add了的,並且cnt從0開始~)
 dfs2(v,u); } } int main() { ios::sync_with_stdio(false); while(cin>>n){ int a,b; init(); for(int i=1;i<n;i++){cin>>a>>b;add_edge(a,b,0);add_edge(b,a,1);} //FOR(i,1,n){dfs(i,i,-1,0);} //用dfs求路程和的複雜度O(n2)超時!!!
        dfs1(1,-1);dfs2(1,-1); //樹形dp O(2n)~~~ //FOR(i,1,n)cout<<dp[i]<<' ';cout<<endl;//         FOR(i,1,n){ if(dp[i]<mi){ cnt=0; mi=dp[i]; k[cnt++]=i; } else if(dp[i]==mi){k[cnt++]=i;} } cout<<mi<<endl; cout<<k[0]; FOR(i,1,cnt-1)cout<<' '<<k[i]; cout<<endl; } return 0; }
相關文章
相關標籤/搜索