【每日一题】7月13日题目精讲—Kingdom
【每日一題】7月13日題目精講—Kingdom
文章目錄
- 題目描述
- 題解:
- 代碼:
題目描述
X王國有n位官員,編號從1到n。國王是1號官員。除了國王以外,每個官員都有一個上司。我們稱這個官員是這個上司的下屬。上司的編號總比下屬小。
我們定義一個官員的影響力為他所有下屬的影響力之和再加1。例如,一個沒有下屬的官員的影響力是1。國王的影響力總是n。
任何一位有下屬的官員總是選擇他的下屬中影響力最高的作為他的心腹(有若干下屬影響力相同的話則會選擇編號最小的)。
一位官員得到一條消息后,他就要把消息傳達給國王。我們定義一位官員的花費為他將消息傳達給國王的花費。國王自己的花費為0。如果一位官員是他上司的心腹,則他的花費等于他上司的花費,否則他的花費為他上司的花費加1。
由于時代和平,消息并不需要傳遞的太快。我們希望你決定每位官員(除了國王)的上司,使得所有官員的花費之和盡量大。
輸入描述:
一個整數n(1≤ n≤ 8000)表示包括國王在內的官員的總數。
輸出描述:
一個整數表示最大的花費之和。
示例1
輸入
復制
輸出
復制
題解:
借鑒自題解
重兒子:父親節點的所有兒子中子樹結點數目最多(size最大)的結點
假設n個節點的排列情況如圖所示
樹根是root,下面是k個子樹
ans[n]為n個節點的數所得的最優解
根據題意我們知道點x的心腹就是點x的重兒子
如果重兒子所在子樹A,我們將重兒子的子樹a與x點分離,看做獨立部分,那么子樹a的最優解就是ans[sumA]
我們再把子樹a連接到x點,因為子樹a是重兒子,重兒子的邊到父節點木有影響,所以最優解還是ans[sumA]
如果子樹A不是重兒子,我們也是先分離看,最優解是ans[sumA],然后連接x點,因為不是重兒子(即心腹),根據題意花費要加一,相當于子樹A中的節點都要加一,加了sumA個1,最優解就是ans[sumA]+sumA
可以結合下圖理解理解
如果重兒子所在子樹是A,其他點就不是重兒子,所得結論:
ans[n]=(ans[sum1]+ans[sum2]+…ans[sumA]…+ans[sumk])+(n?sumA?1)
然后我們用dp[i][j]表示i個節點組成的多個樹,且最多節點的那棵樹節點數不超過j
(該圖選自參考題解)
我們現在要用到ans和dp兩個數組
根據圖片可得:dp[n?sumX?1][sumX]+(n?sumX?1)+ans[sumX]
這樣ans[n]取最大值即可
ans[n]=dp[n?1?sumX][sumX]+(n?1?sumX)+ans[sumX],且1<=sumX<n
dp[i][j]表示i個節點組成的多個樹,且最多節點的那棵樹節點數不超過j,分為兩種情況:
dp[i][j]=dp[i][j-1]//節點數是i,最大樹節點不超過j-1也肯定不超過j
dp[i][j]=dp[i-x][j]+ans[x]//一顆節點數為x的樹和一個節點總數為i-x的森林,合成一個節點數為i的森林,最大節點依舊小于j
兩種情況取最小值
代碼:
#include<bits/stdc++.h> using namespace std; const int maxn=8005; int dp[maxn][maxn]; int ans[maxn]; int main() {int n;cin>>n;for(int i=1;i<=n;i++){for(int j=1;j<i;j++){ans[i]=max(ans[i],ans[j]+dp[i-j-1][j]+(i-j-1));//求出i個節點的樹的最優解 //重兒子所在子樹節點數為j//非重兒子所在子樹節點個數總和為i-j-1 }for(int j=1;j<=n;j++)//有點像完全背包 {if(j>=i)dp[j][i]=max(dp[j][i-1],dp[j-i][i]+ans[i]);else dp[j][i]=dp[j][i-1];}}cout<<ans[n];return 0; }總結
以上是生活随笔為你收集整理的【每日一题】7月13日题目精讲—Kingdom的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 火绒安全软件正式上架Win11应用商店
- 下一篇: 【每日一题】7月14日题目精讲—压缩