树形dp题集(陆续添加)

1.题目链接:https://ac.nowcoder.com/acm/problem/19914

 

题目描述

给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。 

对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色。给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。

输入描述:

第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,…,m,其中编号1,2,… ,n是叶子。
以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],…,c[n]。
以下m-1行每行两个整数a,b(1 ≤ a < b ≤ m),表示结点a和b 有边相连。

输出描述:

仅一个数,即着色结点数的最小值。

示例1

输入

复制

5 3
0
1
0
1 4
2 5
4 5
3 5

输出

复制

2

思路:

假如原来以x为根,y与x相邻,那么x与y的颜色不可能相同。既然颜色不同,那么将根从x变成y对答案显然也不会产生影响。

所以随便选一个点为根,然后树形DP。用dp[x][0/1]表示x的子树中,最后一个点想要得到一个白色/黑色的祖先的最小代价,转移十分容易。

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int n,m;
const int INF=1e4+5;
int c[INF]; 
int head[INF],cnt;
int dp[INF][2];
struct node{
	int di;
	int next;
}f[2*INF];
void init()
{
	int i;
	for(i=0;i<=n;i++)
	{
		head[i]=-1;
	}
	cnt=0;
}
void add(int x,int y)
{
	f[cnt].di =y;
	f[cnt].next =head[x];
	head[x]=cnt++;
}
void dfs(int x,int fa)
{
	dp[x][0]=1;
	dp[x][1]=1;
	if(c[x]==0)
	{
		dp[x][1]=INF;
	}
	if(c[x]==1)
	{
		dp[x][0]=INF;
	}
	int i,j,k,val;
	for(i=head[x];i!=-1;i=f[i].next )
	{
		j=f[i].di ;
		if(j==fa)continue;
		dfs(j,x);
		dp[x][0]+=min(dp[j][0]-1,dp[j][1]);//状态转移方程 
		dp[x][1]+=min(dp[j][1]-1,dp[j][0]);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	int i,j,k,val;
	memset(c,-1,sizeof(c));
	for(i=1,j=0,k=0;i<=m;i++)
	{
		scanf("%d",&c[i]);
	}
	init();
	for(i=1;i

 

 

2.题目链接:https://ac.nowcoder.com/acm/problem/15748

思路:树形dp,最大独立集。

#include//注意所选留宿的城市不一定紧挨着已经游览过的城市 
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int n,s,ans; 
const int INF=5e5+5;
vectorv[INF];
int vis[INF];
int dp[INF][2];
void dfs(int x)
{
	vis[x]=1;
	int cnt;
	dp[x][1]=1;
	cnt=v[x].size();
	int i,j;
	for(i=0;i

 

你可能感兴趣的:(DP)