• 洛谷 P3177 树上染色


    题面

    题目要求将k个点染成黑色,求黑点两两距离及白点两两距离,使他们之和最大。

    我们可以将距离转化为路径,然后再将路径路径拆分成边,就可以记录每条边被经过的次数,直接计算即可。

    很简单对吧?那么问题来了,距离转化为路径好理解,路径拆为边也好说,可是每条边被经过的次数怎么计算呢?

    我们可以这样想,我们任意取两个同色的点,对于每一条边,若不在这两个点的路径上,我们自然不考虑,若是在两个点的路径上,那么这条边的计数加一。我们可以转换一下,若是两个点在边的一侧,则不影响计数,若在边的两侧,则边的计数加一。那么我们推广一下,便可以得出,一条边的两侧每有一对同色点,这条边就要被经过一次。也就是说,一条边被经过的次数等于边的两侧同色点个数的乘积。那么我们便可以求出每条边被经过的次数

    (tot=k*(m-k)+(sz[v]-k)*(n-m-sz[v]+k))

    (m)表示题目要求选的黑点数,(sz[v])表示当前子节点的子树大小,(k)表示当前子节点的子树上已选择的黑点数

    得出了这个结论,我们就可以轻松地DP了。

    下面放代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cctype>
    #define ll long long
    #define gc getchar
    #define maxn 2005
    using namespace std;
    
    inline ll read(){
    	ll a=0;int f=0;char p=gc();
    	while(!isdigit(p)){f|=p=='-';p=gc();}
    	while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    	return f?-a:a;
    }
    
    struct ahaha{
    	int w,to,next;
    }e[maxn<<1];int tot,head[maxn];
    inline void add(int u,int v,int w){
    	e[tot].w=w,e[tot].to=v,e[tot].next=head[u];head[u]=tot++;
    }
    
    int n,m,sz[maxn];
    ll f[maxn][maxn];
    void dfs(int u,int fa){
    	sz[u]=1;f[u][0]=f[u][1]=0;
    	for(int i=head[u];~i;i=e[i].next){
    		int v=e[i].to;if(v==fa)continue;
    		dfs(v,u);sz[u]+=sz[v];
    		for(int j=min(m,sz[u]);j>=0;--j){   //此处倒序枚举是为了避免重复选取
    			if(f[u][j]!=-1)    //在DP前应先加上当前子节点的子树纯白色的情况,这是下面也倒序枚举的前提
    				f[u][j]+=f[v][0]+(ll)sz[v]*(n-m-sz[v])*e[i].w;
    			for(int k=min(j,sz[v]);k;--k){
    				if(f[u][j-k]==-1)continue;
    				ll val=(ll)(k*(m-k)+(sz[v]-k)*(n-m-sz[v]+k))*e[i].w;   //当前情况下连接子节点的边的贡献
    				f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val);
    			}
    		}
    	}
    }
    
    int main(){memset(head,-1,sizeof head);
    	n=read();m=read();
    	if(n-m<m)m=n-m;
    	for(int i=1;i<n;++i){
    		int u=read(),v=read(),w=read();
    		add(u,v,w);add(v,u,w);
    	}memset(f,-1,sizeof f);
    	dfs(1,-1);
    	printf("%lld",f[1][m]);
    	return 0;
    }
    

    以上就是本道题的题解,不知道你是否看懂了呢。如有不明白的地方,欢迎提问。

  • 相关阅读:
    【ARTS】打卡第七周
    【ARTS】打卡第六周
    【ARTS】打卡第五周
    【leetcode】 438. Find All Anagrams in a String
    【ARTS】打卡第四周
    【ARTS】打卡第三周
    【leetcode】 11. Container With Most Water
    【ARTS】打卡第二周
    【ARTS】打卡第一周
    深度VS广度——谈谈对测试职业的一些思考
  • 原文地址:https://www.cnblogs.com/hanruyun/p/9793565.html
Copyright © 2020-2023  润新知