zoukankan      html  css  js  c++  java
  • bzoj 4987 Tree

    Written with StackEdit.

    Description

    从前有棵树。

    找出(K)个点(A_1,A_2,…,A_K)

    使得(∑dis(A_i,A_{i+1}),(1<=i<=K-1))最小。

    Input

    第一行两个正整数(n,k),表示数的顶点数和需要选出的点个数。

    接下来(n-1)行每行3个非负整数(x,y,z),表示从存在一条从(x)(y)权值为(z)的边。

    (1<=k<=n)

    (1<x,y<=n)

    (1<=z<=10^5)

    (n <= 3000)

    Output

    一行一个整数,表示最小的距离和。

    Sample Input

    10 7
    1 2 35129
    2 3 42976
    3 4 24497
    2 5 83165
    1 6 4748
    5 7 38311
    4 8 70052
    3 9 3561
    8 10 80238

    Sample Output

    184524

    Solution

    • 注意到选择的点集一定是两两相邻的.
    • 那么选出的点中,只有一条链可以只经过一次,其余的需要经过两次.
    • 考虑树形背包选边,令(f(i,j,k))表示在子树(i)中选出(j)条边的最小代价,
      • (k=0):回到根节点.
      • (k=1):不回到根节点.
      • (k=2):回到根节点后再下去.
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LoveLive;
    inline int read()
    {
    	int out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		{
    			fh=-1;
    			jp=getchar();
    		}
    	while (jp>='0'&&jp<='9')
    		{
    			out=out*10+jp-'0';
    			jp=getchar();
    		}
    	return out*fh;
    }
    const int MAXN=3e3+10;
    int cnt=0,head[MAXN];
    int nx[MAXN<<1],to[MAXN<<1],val[MAXN<<1];
    inline void add(int u,int v,int w)
    {
    	++cnt;
    	nx[cnt]=head[u];
    	to[cnt]=v;
    	val[cnt]=w;
    	head[u]=cnt;
    }
    int f[MAXN][MAXN][3],siz[MAXN];
    inline void upd(int &x,int y)
    {
    	if(x>y)
    		x=y;
    }
    void dfs(int u,int fa)
    {
    	siz[u]=1;
    	f[u][0][0]=f[u][0][1]=0;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(v==fa)
    				continue;
    			dfs(v,u);
    			for(int j=siz[u]-1;j>=0;--j)
    				for(int k=siz[v]-1;k>=0;--k)
    					for(int l=2;l>=0;--l)
    						for(int m=l;m>=0;--m)
    							upd(f[u][j+k+1][l],f[u][j][l-m]+f[v][k][m]+val[i]*(2-(m & 1)));
    			siz[u]+=siz[v];
    		}
    }
    int n,m;
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<n;++i)
    		{
    			int u=read(),v=read(),w=read();
    			add(u,v,w);
    			add(v,u,w);
    		}
    	memset(f,0x3f,sizeof f);
    	dfs(1,0);
    	int ans=0x7fffffff;
    	for(int i=1;i<=n;++i)
    		for(int j=0;j<=2;++j)
    			ans=min(ans,f[i][m-1][j]);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    参考了dalao的blog.

  • 相关阅读:
    图灵5月书讯※特别制作【MongoDB将在5月中旬隆重上市】
    让你学会狂妄懂得谦卑的书
    一千个读者,一千个不同的编程人生
    松本行弘为什么开发Ruby
    在Flex控件中使用XMLListCollection
    32位系统部署到64位下常见问题及解决
    win7系统的IIS服务器如何解除上传200k限制
    Asp.net单点登录解决方案
    Web.Config加密【转】
    在IIS8添加WCF服务支持
  • 原文地址:https://www.cnblogs.com/jklover/p/10033375.html
Copyright © 2011-2022 走看看