• [HAOI2015]树上染色(树上dp)


    [HAOI2015]树上染色

    这种要算点对之间路径的长度和的题,难以统计每个点的贡献.这个时候一般考虑算每一条边贡献了哪些点对.
    知道这个套路以后,那么这题就很好做了.
    状态:设(dp[u][i])表示u节点(子树里有i个黑点)的子树的边的贡献的和.
    转移:转移就很好想了,知道v内的黑点个数j,知道v内的白点数目(sz[v]-j),知道总共的黑点数目(m),知道总共的白点数目((n-m)),知道边权w,那么转移方程显然就是:

    [dp[u][i]=max{dp[v][j]+w*(m-j)*j+w*(sz_v-j)*[n-m-(sz_v-j)]} ]

    答案就是(dp[1][k])

    #include<bits/stdc++.h>
    #define maxn 2005
    #define ll long long
    using namespace std;
    int n,m,sz[maxn];
    ll dp[maxn][maxn],t[maxn];
    int head[maxn],nxt[maxn<<1],to[maxn<<1],w[maxn<<1],cnt;
    void add(int u,int v,int ww)
    {
    	nxt[++cnt]=head[u];head[u]=cnt;
    	w[cnt]=ww;to[cnt]=v;
    }
    void dfs(int u,int ff)
    {
    	dp[u][0]=dp[u][1]=0;sz[u]=1;
    	for(int ii=head[u];ii;ii=nxt[ii])
    	{
    		int v=to[ii];if(v==ff)continue;
    		dfs(v,u);sz[u]+=sz[v];
    		for(int i=0;i<=m;i++)t[i]=dp[u][i];
    		for(int i=m;i>=0;i--)
    		{
    			for(int j=0;j<=min(i,sz[v]);j++)
    			{
    				if(t[i-j]==-1)continue;ll res=0,ww=w[ii];
    				res=dp[v][j]+ww*(m-j)*j+ww*(sz[v]-j)*(n-m-sz[v]+j);
    				//cout<<u<<" "<<v<<" "<<ww<<" "<<i<<" "<<j<<endl;
    				dp[u][i]=max(dp[u][i],res+t[i-j]);
    			}
    		}
    		//cout<<u<<"&"<<v<<" ";
    		//for(int i=0;i<=m;i++)cout<<dp[u][i]<<" ";cout<<endl;
    	}
    }
    int main()
    {
    	cin>>n>>m;
    	for(int i=1,u,v,ww;i<n;i++)
    		scanf("%d%d%d",&u,&v,&ww),add(u,v,ww),add(v,u,ww);
    	memset(dp,-1,sizeof(dp));
    	dfs(1,0);cout<<dp[1][m]<<endl;
    	//for(int u=1;u<=n;u++,cout<<endl)
    	//	for(int i=0;i<=m;i++)
    	//		cout<<dp[u][i]<<" ";
    	return 0;
    }
    
    
  • 相关阅读:
    fastjson对String、JSONObject、JSONArray相互转换
    查看各进程分别占用多少服务器内存
    如何关闭或删除阿里云云盾安骑士
    docker 镜像操作
    docker 容器命令
    docker换源
    centos8 docker安装
    基本概念
    自动生成文件注释和函数注释
    Pycharm新建文件时自动添加基础信息
  • 原文地址:https://www.cnblogs.com/terribleterrible/p/9861158.html
Copyright © 2020-2023  润新知