hdu4003 树形dp

http://www.cnblogs.com/kuangbin/archive/2012/08/29/2661928.html


【转载】:

dp[i][j]表示对于以i结点为根结点的子树,放j个机器人所需要的权值和。 

当j=0时表示放了一个机器人下去,遍历完结点后又回到i结点了。状态转移方程类似背包 

如果最终的状态中以i为根结点的树中有j(j>0)个机器人,那么不可能有别的机器人r到了这棵树后又跑到别的树中去 

因为那样的话,一定会比j中的某一个到达i后跑与r相同的路径再回到i,再接着跑它的路径要差(多了一条i回去的边) 

这样的话,如果最后以i为根结点的树中没有机器人,那么只可能是派一个机器人下去遍历完后再回来

————————————————————————————————————————————————

状态转移,使用的“分组背包”思想。

使用一维数组的“分组背包”伪代码如下:

for 所有的组i

    for v=V..0

        for 所有的k属于组i

            f[v]=max{f[v],f[v-c[k]]+w[k]}

——————

可以这么理解:

对于每个根节点root,有个容量为K的背包

如果它有i个儿子,那么就有i组物品,价值分别为dp[son][0],dp[son][1].....dp[son][k] ,这些物品的重量分别为0,1,.....k

现在要求从每组里选一个物品(且必须选一个物品)装进root的背包,使得容量不超过k的情况下价值最大。

那么这就是个分组背包的问题了。

但是这里有一个问题,就是每组必须选一个物品。

对于这个的处理,我们先将dp[son][0]放进背包,如果该组里有更好的选择,那么就会换掉这个物品,否则的话这个物品就是最好的选择。这样保证每组必定选了一个。



#include <iostream>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f
#define BUG printf("here!\n")
using namespace std;
struct node
{
    int u,v,w;
};
node edge[30000];
int first[15000],next[30000],cc;
int dp[30000][12];
int N,S,K;
inline void add_edge(int u,int v,int w)
{
    edge[cc].u=u;
    edge[cc].v=v;
    edge[cc].w=w;
    next[cc]=first[u];
    first[u]=cc;
    cc++;

    edge[cc].v=u;
    edge[cc].u=v;
    edge[cc].w=w;
    next[cc]=first[v];
    first[v]=cc;
    cc++;
}
void dfs(int u,int p)
{
    int i;
    for(i=first[u];i!=-1;i=next[i])
    {
        int v=edge[i].v;
        if(v==p)
            continue;
        dfs(v,u);
        int j,k;
        for(j=K;j>=0;j--)
        {
            dp[u][j]+=dp[v][0]+2*edge[i].w;
            for(k=1;k<=j;k++)
            {
                dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+k*edge[i].w);
            }
        }
    }
}
int Scan()
{
	int res = 0, ch, flag = 0;
	if((ch = getchar()) == '-')				//判断正负
		flag = 1;

	else if(ch >= '0' && ch <= '9')			//得到完整的数
		res = ch - '0';
	while((ch = getchar()) >= '0' && ch <= '9' )
		res = res * 10 + ch - '0';

	return flag ? -res : res;
}
int main()
{

    while(scanf("%d%d%d",&N,&S,&K)!=EOF)
    {
        int i;
        memset(first,-1,sizeof(first));
        memset(next,-1,sizeof(next));
        cc=0;
        memset(dp,0,sizeof(dp));
        for(i=0;i<N-1;i++)
        {
            int u,v,w;
            u=Scan();
            v=Scan();
            w=Scan();
            add_edge(u,v,w);
        }
        dfs(S,-1);
        printf("%d\n",dp[S][K]);
    }
    return 0;
}


你可能感兴趣的:(hdu4003 树形dp)