POJ - 4045 Power Station(树形dp/树的重心)
題目鏈接:點(diǎn)擊查看
題目大意:給出一個n個節(jié)點(diǎn)的樹,我們需要選出一個節(jié)點(diǎn),到其余任何節(jié)點(diǎn)的距離和最小
題目分析:這個題我的第一反應(yīng)是用樹的重心,先求出來符合條件的點(diǎn),然后再跑一遍dfs求距離,最后輸出就好,因?yàn)闃涞闹匦牡亩x是子樹節(jié)點(diǎn)<= n/2, 而每一棵樹的重心不會超過2個,所以記錄答案的時候也變得簡單了許多,去網(wǎng)上查了一下沒查到用樹的重心做的題解,還以為是自己思路想錯了,但是自己寫寫試試之后果不其然的過了,和預(yù)想的一樣(yeah!!)然后還有一個方法,是先跑一邊dfs求出子樹的節(jié)點(diǎn)數(shù),以及子樹到根節(jié)點(diǎn)的距離和,在跑一邊dfs求出除了子樹外的點(diǎn)到根節(jié)點(diǎn)的距離和,先求出最小的距離和,然后遍歷一遍n個頂點(diǎn),找到符合條件的點(diǎn)輸出答案即可。
上述方法中涉及到了幾個變量的維護(hù)都需要用樹形dp來維護(hù),我來稍微解釋一下其轉(zhuǎn)移方程吧
首先是維護(hù)子樹節(jié)點(diǎn),這個最簡單,只需要自底向上,根節(jié)點(diǎn)依次累加子節(jié)點(diǎn)的答案即可。
其次是關(guān)于樹的重心的方法中,已知符合條件的點(diǎn),再維護(hù)距離,這個需要在累加子節(jié)點(diǎn)答案的基礎(chǔ)上,每次最后再加一遍該節(jié)點(diǎn)的子樹上的節(jié)點(diǎn)數(shù)量,因?yàn)榍蟮檬蔷嚯x和,之前累加子節(jié)點(diǎn)的答案求出來的是子樹上的點(diǎn)到子節(jié)點(diǎn)的距離和,而它們到達(dá)根節(jié)點(diǎn)還差一個單位的距離,每個點(diǎn)都差一個單位的距離,總共就差了該根節(jié)點(diǎn)子樹上的點(diǎn)的個數(shù)的距離了。
然后就是關(guān)于第二個方法了,第二個方法中需要維護(hù)三個數(shù)組,一個是剛才提到的子樹節(jié)點(diǎn)數(shù)量,這里用num數(shù)組記錄,還有一個是維護(hù)子樹中節(jié)點(diǎn)到根節(jié)點(diǎn)的距離和,這里用dp[i][0]數(shù)組維護(hù),這兩個數(shù)組上述已經(jīng)解釋過了,下面解釋一下最后一個不太好理解的,dp[i][1],表示除了子樹外的點(diǎn)到根節(jié)點(diǎn)的距離和。其實(shí)說是不好理解只是因?yàn)橛悬c(diǎn)抽象,我先把公式放出,先不化簡,然后具體解釋具體意義,應(yīng)該就不難理解了:
dp[v][1]=(n-num[v])+(dp[u][1])+(dp[u][0]-(dp[v][0]+num[v]));
依次轉(zhuǎn)換成偽代碼,就變成了:(以下使用“其他的點(diǎn)”來代替“除了子樹節(jié)點(diǎn)外的點(diǎn)”,并且“該點(diǎn)”以及“父節(jié)點(diǎn)”指的都是“當(dāng)前節(jié)點(diǎn)”和“當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)”)
其他的點(diǎn)到達(dá)該點(diǎn)的距離和=(其他的點(diǎn)的數(shù)量)+(其他的點(diǎn)到父節(jié)點(diǎn)的距離和)+(父節(jié)點(diǎn)的子樹到父節(jié)點(diǎn)的距離和-(包含該點(diǎn)在內(nèi)的子樹到父節(jié)點(diǎn)的距離))
可能這幾行文字能把人繞暈。。因?yàn)閷?shí)在是太抽象了,如果實(shí)在想不過來,可以自己畫個圖,就一目了然了,本質(zhì)就是一個區(qū)間分成了的各個部分。
直接上代碼了:
樹的重心:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<cmath> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=5e4+100; int n,I,R;int num[N];vector<int>node[N];int ans,mark1,mark2;LL dp[N];//記錄距離和 void dfs(int u,int fa) {int mmax=-1;num[u]=1;for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==fa)continue;dfs(v,u);mmax=max(mmax,num[v]);num[u]+=num[v];}mmax=max(mmax,n-num[u]);if(ans>mmax){ans=mmax;mark1=u;mark2=-1;}else if(ans==mmax)mark2=u; }void dfs2(int u,int fa) {num[u]=1;for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==fa)continue;dfs2(v,u);num[u]+=num[v];dp[u]+=dp[v]; }dp[u]+=num[u]-1; }int main() { // freopen("input.txt","r",stdin)int w;cin>>w;while(w--){scanf("%d%d%d",&n,&I,&R);for(int i=1;i<=n;i++)node[i].clear();for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}memset(dp,0,sizeof(dp));mark1=mark2=-1;ans=inf;dfs(1,-1);dfs2(mark1,-1);cout<<dp[mark1]*I*I*R<<endl;if(mark2!=-1){cout<<min(mark1,mark2)<<' '<<max(mark1,mark2)<<endl;}else{cout<<mark1<<endl;}cout<<endl;}return 0; }傳統(tǒng)做法:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<cmath> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=5e4+100; int n,I,R;int num[N];LL ans;vector<int>node[N];LL dp[N][2];//記錄距離:dp[i][0]表示該節(jié)點(diǎn)的子樹到該點(diǎn)的距離和,dp[i][1]表示除了該節(jié)點(diǎn)子樹外的點(diǎn)到該點(diǎn)的距離和void dfs(int u,int fa) {num[u]=1;for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==fa)continue;dfs(v,u);num[u]+=num[v];dp[u][0]+=dp[v][0];}dp[u][0]+=num[u]-1; }void dfs2(int u,int fa) {for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==fa)continue;dp[v][1]=dp[u][1]+n-num[v]+dp[u][0]-dp[v][0]-num[v];dfs2(v,u);}ans=min(ans,dp[u][1]+dp[u][0]); }int main() { // freopen("input.txt","r",stdin)int w;cin>>w;while(w--){scanf("%d%d%d",&n,&I,&R);for(int i=1;i<=n;i++)node[i].clear();for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}memset(dp,0,sizeof(dp));dfs(1,-1);ans=inf;dfs2(1,-1);bool first=true;cout<<ans*I*I*R<<endl;for(int i=1;i<=n;i++){if(dp[i][0]+dp[i][1]==ans){if(first)first=false;elsecout<<' ';cout<<i;}}cout<<endl<<endl;}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的POJ - 4045 Power Station(树形dp/树的重心)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SPOJ - BALNUM Balanc
- 下一篇: FZU - 2218 Simple St