Team Asobi正式成為索尼旗下工作室 新Logo公佈
阿新 • • 發佈:2021-06-03
題面
一個樹形dp,
我們根據題意去想如何得到兩兩距離,發現一條邊的兩側每有一對同色點,這條邊就要被經過一次
在當前的子節點的子樹中,列舉有k個黑點,需要一個在其他子樹中選了共 j - k 個黑點的狀態
code
#include<bits/stdc++.h> #define int long long using namespace std; int n,m; int dp[2021][2021]; //i為根j個黑點 int head[4022],nxt[4022],to[4022],edge[4022]; int siz[2022]; int _; void add(intx,int y,int z) { _++; edge[_]=z; to[_]=y; nxt[_]=head[x]; head[x]=_; return ; } //看邊經過次數 void makedp(int x,int fa) { siz[x]=1; dp[x][0]=0; dp[x][1]=0; //兩種必然存在的結果 for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==fa) continue; makedp(y,x); siz[x]+=siz[y]; //減少範圍,最多子樹全是 黑點 for(int j=min(m,siz[x]);j>=0;j--) {//最多是兒子的子樹全是 ,我們嘗試去更新已知 for(int k=0;k<=min(j,siz[y]);k++) {//子樹超了,狀態不河狸 if(dp[x][j-k]==-1) continue; //edge[i]*k*(m-k) + edge[i]*(siz[y]-k)*(n-m-siz[y]+k)//邊權*個數*個數(左右)(假設去染) +邊權*子樹個數*除這個子子樹(未染) //當前點的j兒子=max(自身,兒子的dp值(有兩個,黑/白)+) // 白, 黑 dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]+edge[i]*k*(m-k)+edge[i]*(siz[y]-k)*(n-m-siz[y]+k)); } } } return ; } signed main() { ios::sync_with_stdio(false); cin>>n>>m; memset(dp,-1,sizeof(dp)); for(int i=1;i<n;i++) { int q,w,e; cin>>q>>w>>e; add(q,w,e); add(w,q,e); } makedp(1,0); //根節點1,有m個黑點 cout<<dp[1][m]; return 0; }