【題解】 bzoj4033: [HAOI2015]樹上染色* (動態規劃)
阿新 • • 發佈:2018-04-29
規劃 math online 4.2 pro php 白色 AD truct
bzoj4033,懶得復制,戳我戳我
Solution:
- 定義狀態\(dp[i][j]\)表示\(i\)號節點為根節點的子樹裏面有\(j\)個黑色節點時最大的貢獻值
- 然後我們要知道的就是子節點到根節點這條邊會計算次數就是:子樹中白色節點數\(*\)子樹外白色節點數\(+\)子樹中黑色節點數\(*\)子樹外黑色節點數
\[dp[u][j+k]=max(dp[u][j+k],\]
\[dp[u][j]+dp[v][k]+(1ll)*k*(m-k)*dis[v]+(1ll)*(siz[v]-k)*(n-m-siz[v]+k)*dis[v])\] - 丟個鏈接
Attention:
- 樹上背包dp註意操作:
這樣可以保證時間復雜度是\(O(n^2)\),每次會保證是從已經獲得的dp值推向未知的,就不會有多余的操作,所以我們每次枚舉要添加的節點數目,加到已經求出前面幾棵子樹節點數目中
for(int j=min(m,siz[u]);j>=0;j--){ int box=min(m,siz[v]); for(int k=box;k>=0;k--){ dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]+1ll*k*(m-k)*dis[v]+1ll*(siz[v]-k)*(n-m-siz[v]+k)*dis[v]); } }siz[u]+=siz[v];
Code:
//It is coded by Ning_Mew on 4.24
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=2000+7;
int n,m,fa[maxn];
LL dp[maxn][maxn];
int siz[maxn],dis[maxn];
int head[maxn],cnt=0;
struct Edge{int nxt,to,dis;}edge[maxn*2];
void add(int from,int to,int dis){
edge[++cnt].nxt=head[from];
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
void dfs(int u){
siz[u]=1;//dp[u][0]=dp[u][1]=0;
for(int i=head[u];i!=0;i=edge[i].nxt){
int v=edge[i].to; if(v==fa[u])continue;
dis[v]=edge[i].dis; fa[v]=u;
dfs(v); //siz[u]+=siz[v];
for(int j=min(m,siz[u]);j>=0;j--){
int box=min(m,siz[v]);
for(int k=box;k>=0;k--){
dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]+1ll*k*(m-k)*dis[v]
+1ll*(siz[v]-k)*(n-m-siz[v]+k)*dis[v]);
}
}siz[u]+=siz[v];
}return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;i++){
int u,v,diss;scanf("%d%d%d",&u,&v,&diss);
add(u,v,diss);add(v,u,diss);
}
dfs(1);
printf("%lld\n",dp[1][m]);
return 0;
}
【題解】 bzoj4033: [HAOI2015]樹上染色* (動態規劃)