树形DP

本文介绍了树形动态规划(Tree DP)的概念,并通过两个实例——MZOJ1063 士兵守卫和MZOJ1264 longest——详细讲解了如何应用树形DP解决实际问题。在士兵守卫问题中,目标是在树形结构中用最少的士兵覆盖所有边;在最长路径问题中,任务是找到树中两个城市间的最长路径。每个例题都包含题目描述、输入输出格式、样例及解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树形DP

【例题1】MZOJ1063 士兵守卫

http://61.139.95.227:82/problem.php?id=1063

题目描述

Bob特别喜欢战略游戏,但有时他不能尽快找到最优解,所以他就很伤心。现在他又有一个问题,他必须保卫一个中世纪的城市,这个城市的道路形成了一棵树。他需要在树的节点上放最少的士兵来观察所有的边。你能帮助他么?

例如下图就只需要一个士兵放在1号节点。在这里插入图片描述

输入

输入文件中有多组数据,每组数据的第一行N表示点的个数。接下来N行每行格式如下
x:(k) a1 a2 … ak(x为点的编号,k为与其相连的子节点个数,a1, a2, …, ak分别为子节点的编号)

输出

对于每组数据输出一行一个数,即最少士兵数。

样例输入

4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)

样例输出

1
2

提示

0 < N<= 1500, 0
0 <= x < N

【代码】
#include <bits/stdc++.h>
using namespace std;

const int MAXN=15000+5;
int n,f[MAXN][5];

int size=0;
int head[MAXN];
struct node
{
	int u;
	int v;
	int next;
}edge[MAXN<<1];

void add(int u,int v)
{
	edge[size].u=u;
	edge[size].v=v;
	edge[size].next=head[u];
	head[u]=size++;
}

inline int read()
{
	int X=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') 
	{
		X=(X<<1)+(X<<3)+ch-'0';
		ch=getchar();
	}
	return X;
}

void dp(int u,int fa)
{
	f[u][0]=0; f[u][1]=1;
	for(int i=head[u];~i;i=edge[i].next)
	{
		int v=edge[i].v;
		if(v==fa) continue;
		dp(v,u);
		f[u][0]+=f[v][1];
		f[u][1]+=min(f[v][0],f[v][1]);
	}
}

int main()
{
	freopen("input.txt","r",stdin);
	while(scanf("%d",&n)!=EOF)
	{
		memset(head,-1,sizeof(head));
		int u,v,t;
		for(int i=1;i<=n;i++)
		{
			scanf("%d:(%d)",&u,&t);
		    for(int i=1;i<=t;i++)
		    {
			    scanf("%d",&v);
			    add(u,v);
			    add(v,u);
		    }
		}
		dp(0,-1);
		printf("%d\n",min(f[0][0],f[0][1]));
	}
	return 0;
}

【例题2】 MZOJ1264 longest

http://61.139.95.227:82/problem.php?id=1264

题目描述

乌托邦有n个城市,某些城市之间有公路连接。任意两个城市都可以通过公路直接或者间接到达,并且任意两个城市之间有且仅有一条路径(What does this imply? A tree!)。

每条公路都有自己的长度,这些长度都是已经测量好的。

小修想从一个城市出发开车到另一个城市,并且她希望经过的公路总长度最长。请问她应该选择哪两个城市?这个最长的长度是多少?

输入

第一行n(n<=1000)。

以下n-1行每行三个整数a, b, c。表示城市a和城市b之间有公路直接连接,并且公路的长度是c(c<=10000)。

输出

仅一个数,即最长长度。

样例输入

5

1 2 2

2 3 1

2 4 3

1 5 4

样例输出

9

说明

从城市4到城市5,经过的路径是4-2-1-5,总长度是9。

#include <bits/stdc++.h>
using namespace std;

const int MAXN=1005;
int n,ans=0,f[MAXN][5];

int size=0;
int head[MAXN];
struct node
{
	int u;
	int v;
	int w;
	int next;
}edge[MAXN<<1];

void add(int u,int v,int w)
{
	edge[size].u=u;
	edge[size].v=v;
	edge[size].w=w;
	edge[size].next=head[u];
	head[u]=size++;
}

inline int read()
{
	int X=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') 
	{
		X=(X<<1)+(X<<3)+ch-'0';
		ch=getchar();
	}
	return X;
}

inline int write(int X)
{
	if(X<0) {putchar('-'); X=~(X-1);}
	int s[20],top=0;
	while(X) {s[++top]=X%10; X/=10;}
	if(!top) s[++top]=0;
	while(top) putchar(s[top--]+'0');
}

void readdata()
{
	memset(head,-1,sizeof(head));
	n=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read(),w=read();
		add(u,v,w);
		add(v,u,w);
	}
}

void dp(int u,int fa)
{
	f[u][0]=0; f[u][1]=0;
	for(int i=head[u];~i;i=edge[i].next)
	{
		int v=edge[i].v,w=edge[i].w;
		if(v==fa) continue;
		dp(v,u);
		int dis=f[v][0]+w;
		if(dis>f[u][0])
		{
			f[u][1]=f[u][0];
			f[u][0]=dis;
		}
		else if(dis>f[u][1])
		{
			f[u][1]=dis;
		}
		ans=max(ans,f[u][1]+f[u][0]);
	}
}

void work()
{
	dp(1,0);
	write(ans);
}

void init()
{
	freopen("input.txt","r",stdin);
//	freopen("output.txt","w",stdout);
}

int main()
{
	init();
	readdata();
	work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值