1. 程式人生 > 其它 >P3478 [POI2008]STA-Station(換根dp)

P3478 [POI2008]STA-Station(換根dp)

技術標籤:動態規劃

題目傳送門

題意: 有一顆樹,問你選哪個節點為根節點時,所有節點深度之和最大?

思路: 先以1為根,求出每個點的深度和以該節點為根的子樹大小。 f [ x ] f[x] f[x]表示以x為根節點時,所有節點的深度之和,再深搜一遍,如果y是x的子節點,那麼 f [ y ] = f [ x ] − s i z [ y ] + ( n − s i z [ y ] ) f[y]=f[x]-siz[y]+(n-siz[y]) f[y]=f[x]siz[y]+(nsiz[y]),即從x作為根節點轉化成從y作為根節點,y的子樹中所有點的深度-1,其他所有點深度+1,從而得到了這個狀態轉移式。

程式碼:

#include<bits/stdc++.h>
#define endl '\n'
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define pii pair<int,int>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
char *fs,*ft,buf[1<<
20]; #define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++; inline int read() { int x=0,f=1; char ch=gc(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=gc(); } while(ch>='0'&&ch<='9') { x=
x*10+ch-'0'; ch=gc(); } return x*f; } using namespace std; const int N=1e6+10; const int inf=0x3f3f3f3f; const int mod=1e9+7; const double eps=1e-7; vector<int>e[N]; int siz[N],f[N],dep[N],n; void dfs(int fa,int x,int d) { siz[x] = 1; dep[x] = d; for(auto i:e[x]) { if(i!=fa) { dfs(x,i,d+1); siz[x] += siz[i]; } } } void ddfs(int fa,int x) { for(auto i:e[x]) { if(i!=fa) { f[i] = f[x] - siz[i] + (n-siz[i]); ddfs(x,i); } } } void solve() { cin>>n; for(int i=1;i<=n-1;i++) { int u,v; cin>>u>>v; e[u].pb(v); e[v].pb(u); } dfs(1,1,1); for(int i=1;i<=n;i++) { f[1] += dep[i]; } ddfs(1,1); int res,ma=-1; for(int i=1;i<=n;i++) { if(f[i]>ma) { ma=f[i]; res=i; } } cout<<res<<endl; } signed main() { solve(); return 0; }