[洛谷P2015] 二叉蘋果樹
阿新 • • 發佈:2019-02-09
題目描述
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有隻有1個兒子的結點)
這棵樹共有N個結點(葉子點或者樹枝分叉點),編號為1-N,樹根編號一定是1。
我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹
2 5
\ /
3 4
\ /
1
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。
給定需要保留的樹枝數量,求出最多能留住多少蘋果。
輸入輸出格式
輸入格式:
第1行2個數,N和Q(1<=Q<= N,1<N<=100)。
N表示樹的結點數,Q表示要保留的樹枝數量。接下來N-1行描述樹枝的資訊。
每行3個整數,前兩個是它連線的結點的編號。第3個數是這根樹枝上蘋果的數量。
每根樹枝上的蘋果不超過30000個。
輸出格式:
一個數,最多能留住的蘋果的數量。
輸入輸出樣例
輸入樣例#1:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
輸出樣例#1:
21
比較基礎的樹形dp,以每個節點及節點對應剪枝數為狀態,容易得出方程
其中 u,v 表示當前節點及子節點,i j 表示當前狀態還有多少枝條可剪
由於核心部分由遞推實現,j 的更新順序應該從大到小,防止覆蓋
程式碼
#include<cstdio> #include<iostream> #include<vector> #include<algorithm> using namespace std; int n,q; const int N=101; int d[N][N]; struct edge { int to; int w; edge(int v,int s):to(v),w(s){} }; vector<edge> G[N]; void dp(int u,int fa) { for(int i=0;i<G[u].size();i++) { edge v=G[u][i]; if(v.to==fa) continue; dp(v.to,u); for(int i=q;i>=0;i--) for(int j=0;j<i;j++) d[u][i]=max(d[u][i],d[u][j]+d[v.to][i-j-1]+v.w); } } int main() { scanf("%d%d",&n,&q); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); G[u].push_back(edge(v,w)); G[v].push_back(edge(u,w)); } dp(1,-1); printf("%d\n",d[1][q]); return 0; }
這是我第一次寫的,很沒有條理的搜尋,un記錄了每個節點位於限制狀態下的剪枝狀態,事實上沒必要考慮限制,因為更新過程是從頂到底層層搜尋,不會訪問到不需要的部分
不過這還是有優點的,這是一次漂亮的狀態壓縮啊!(滑稽)
#include<cstdio> #include<iostream> #include<vector> #include<algorithm> using namespace std; int n,q,tot=0; const int N=101; int d[N][N]; struct edge { int to; int w; edge(int v,int s):to(v),w(s){} }; vector<edge> G[N]; int dp(int u,int fa,int un) { int &ans=d[u][un]; if(tot>=un) return ans=0;//邊界 if(ans) return ans;//記憶化 edge x=edge(0,0); edge y=edge(0,0); for(int i=0;i<G[u].size();i++) { edge v=G[u][i]; if(v.to == fa) continue; if(x.to==0) x=v; else y=v; } int maxx=0; if(x.to!=0) {tot++; maxx=max(maxx,dp(x.to,u,un)+x.w); tot--;} if(y.to!=0) {tot++; maxx=max(maxx,dp(y.to,u,un)+y.w); tot--;} if(x.to!=0 && y.to !=0 && tot+2 <= un) for(int i=tot;i<=un;i++) { int ans1=0,ans2=0; tot+=1; if(tot <= i) ans1=dp(x.to,u,i)+x.w;tot-=1; tot+=1; if(tot <= un-i+tot-1) ans2=dp(y.to,u,un-i+tot-1)+y.w;tot-=1; maxx=max(maxx,ans1+ans2); } return ans=maxx; } int main() { scanf("%d%d",&n,&q); for(int i=1;i<n;i++) { int u,v,va; scanf("%d%d%d",&u,&v,&va); G[u].push_back(edge(v,va)); G[v].push_back(edge(u,va)); } int ans=dp(1,-1,q); printf("%d\n",ans); return 0; }
衍生題目:選課