zoukankan      html  css  js  c++  java
  • [HAOI2015]树上染色

    题意

    给一棵(n)个点的边带权的树,要求选(k)个点染成白色,其他点为黑色,最大化(黑点两两距离+白点两两距离),((nleq 2000))

    思路

    一道好题,思路不容易get,但是想出来之后很简单

    一般树形DP的套路:设(f_{rt,i})表示以(rt)为根的子树选(i)个点染成白色,这棵子树白点两两距离和;然后发现不会转移了qwq

    为什么这样做不行呢?因为这棵子树白点的贡献并不仅限于这棵子树,也就是说这棵子树中的白点需要和子树外的白点统计距离,但是状态的定义使得我们只能统计子树内的白点两两距离,合并状态的时候由于不知道白点的分布而不能求子树间白点的贡献


    考虑边的贡献,即可完美解决这个问题

    一条边的贡献为:(wi imes) (() 一边的白点数( imes)另一边的白点数(+)一边的黑点数( imes)另一边的黑点数()),于是设(f_{rt,i})表示以(rt)为根的子树中选择(i)个点染为白色时,这棵子树中所有边的贡献

    可以发现转移就是个树形背包,于是就这么搞就完事了

    Code

    #include<bits/stdc++.h>
    #define N 2005
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    int n,m,size[N];
    ll f[N][N];
    struct Edge
    {
    	int next,to;
    	ll dis;
    }edge[N<<1];int head[N],cnt=1;
    void add_edge(int from,int to,ll dis)
    {
    	edge[++cnt].next=head[from];
    	edge[cnt].to=to;
    	edge[cnt].dis=dis;
    	head[from]=cnt;
    }
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    void dfs(int rt,int fa)
    {
    	size[rt]=1;
    	f[rt][0]=f[rt][1]=0;
    	for(int i=head[rt];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(v==fa) continue;
    		dfs(v,rt);
    		size[rt]+=size[v];
    		for(int j=Min(size[rt],m);j>=0;--j)
    		{
    			for(int k=0;k<=Min(j,size[v]);++k)
    			{
    				ll val = edge[i].dis*((ll)k*(m-k) + (ll)(size[v]-k)*(n-m-size[v]+k));
    				f[rt][j]=Max(f[rt][j] , f[v][k] + f[rt][j-k] + val);
    			}
    		}
    	}
    }
    int main()
    {
    	read(n);read(m);
    	for(int i=1;i<n;++i)
    	{
    		int x,y; ll z;
    		read(x);read(y);read(z);
    		add_edge(x,y,z);
    		add_edge(y,x,z);
    	}
    	memset(f,-50,sizeof(f));
    	dfs(1,0);
    	cout<<f[1][m]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    抽象工厂例子
    学习boost::asio一些小例子
    boost::asio学习(定时器)
    共享内存
    网络流程图
    粘包
    端游服务器群
    38 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
    37 有n个人围成一圈,顺序排号,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号那位.
    36 有n个整数,使其前面各数顺序向后移n个位置,最后m个数变成最前面的m个数
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11789305.html
Copyright © 2011-2022 走看看