1. 程式人生 > >[HAOI2015]樹上染色

[HAOI2015]樹上染色

space fine calc def 黑點 ret printf sum long long

題目描述(bzoj)

同上(洛谷)

思路

樹形DP
size[i]:i子樹的節點個數
f[i][j]:在i子樹中染j個黑點的最大貢獻
更新時考慮每條邊對答案的貢獻
即:這條邊兩側的黑點個數乘積*邊權+兩側白點個數乘積*邊權
然後是註意開long long,要不然一半分就沒了╮(╯_╰)╭

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 2005
int n,k;
struct edge{
    int u,v,nxt;
    long long
dis; }e[N*2]; int cnt,first[N]; void add_edge(int x,int y,int z){ e[++cnt].u=x; e[cnt].v=y; e[cnt].dis=z; e[cnt].nxt=first[x]; first[x]=cnt; } bool vis[N]; int size[N]; long long f[N][N]; long long calc(long long dis,int siz,int y){ dis*=(y*(k-y)+(siz-y)*(n-k-siz+y)); return
dis; } void dfs(int u){ vis[u]=true; size[u]=1; for(int i=first[u];i;i=e[i].nxt){ int v=e[i].v; if(!vis[v]){ dfs(v); for(int x=size[u];x>=0;x--){ for(int y=size[v];y>=0;y--){ long long sum=f[u][x]+f[v][y]+calc(e[i].dis,size[v],y); f[u][x
+y]=max(f[u][x+y],sum); // printf("when size[%d]=%d,f[%d][%d]=%d\n",u,size[u],x,x+y,f[x][x+y]); } } size[u]+=size[v]; } } } int main(){ scanf("%d%d",&n,&k); for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add_edge(x,y,z); add_edge(y,x,z); } dfs(1); long long ans=f[1][k]; printf("%lld\n",ans); return 0; }

[HAOI2015]樹上染色