• [haoi2015]T1


     题意:给定你一颗树,要求你在这棵树中确定K个黑点和N-K个白点,使黑点间与白点间两两距离之和最大,输出最大值.n<=2000

     对于这道题,我想了好几个思路,包括点分治,贪心,动规,网络流等等,实在无法,敲了个贪心,但最后结果出来后题解是树形动规.

     动规尤其树形动规我也做过不少,这道题给了我很大启发.

     梳理一下我最初的否决的思路:设f[i][j]表示向i子树加入j个黑点所得到的最大收益,但我发现这样搞一是不好转移,二是后效性没有解除,三是复杂度惊人,就放弃了.

     得到正解之后,又仔细想了一下,有一个很明显的东西是,一个子树内部无论结构如何,只要确定它的黑点白点个数,对外面的影响就是确定的,这就是后效性的解释.

     转移可以视为背包,至于复杂度,复杂度ydc有专门的解释.

     这题就没什么了.

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iomanip>
    using namespace std;
    #define LL long long
    #define up(i,j,n) for(int i=j;i<=n;i++)
    #define pii pair<int,int>
    #define db double
    #define eps 1e-4
    #define FILE "dealing"
    int read(){
    	int x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
    	return x*f;
    }
    const LL maxn=2200,inf=10000000000000LL;
    bool cmin(int& a,int b){return a>b?a=b,true:false;}
    //bool cmax(int& a,int b){return a<b?a,b,true:false;}
    bool cmin(LL& a,LL b){return a>b?a=b,true:false;}
    int n,K;
    struct node{
    	int y,next,v;
    }e[maxn<<1];
    int linkk[maxn],len=0;
    void insert(int x,int y,int v){e[++len].v=v;e[len].next=linkk[x];linkk[x]=len;e[len].y=y;}
    LL f[maxn][maxn],siz[maxn],fa[maxn];
    void dfs(int x){
    	siz[x]=1;
    	f[x][0]=f[x][1]=0;
    	for(int i=linkk[x];i;i=e[i].next){
    		if(e[i].y==fa[x])continue;
    		fa[e[i].y]=x;
    		dfs(e[i].y);
    		siz[x]+=siz[e[i].y];
    		for(int j=siz[x];j>=0;j--){
    			for(int k=0;k<=siz[e[i].y]&&k<=j;k++){
    				LL ans=k*(K-k)+(siz[e[i].y]-k)*(n-K-(siz[e[i].y]-k));
    				ans*=e[i].v;
    				ans+=f[e[i].y][k];
    				f[x][j]=max((LL)f[x][j],f[x][j-k]+ans);
    			}
    		}
    	}
    }
    int main(){
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    	n=read(),K=read();
    	memset(f,-10,sizeof(f));
    	up(i,1,n-1){
    		int x=read(),y=read(),v=read();
    		insert(x,y,v);insert(y,x,v);
    	}
    	dfs(1);
    	cout<<f[1][K]<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    redis的实现过程
    文件流的操作
    已知json类型根据类型封装集合
    linq小知识总结
    设计模式之策略模式
    jq实现竞拍倒计时
    SqlDependency缓存数据库表小案例
    渗透之路基础 -- 初窥文件解析漏洞
    渗透之路基础 -- 文件上传
    渗透之路进阶 -- SQL注入进阶(盲注和报错注入)
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6476502.html
Copyright © 2020-2023  润新知