Codeforces 461B - Appleman and Tree 树状DP

一棵树上有K个黑色节点,剩余节点都为白色,将其划分成K个子树,使得每棵树上都只有1个黑色节点,共有多少种划分方案。

个人感觉这题比较难。假设dp(i,0..1)代表的是以i为根节点的子树种有0..1个黑色节点的划分方案数。

当节点i为白色时,对于它的每个孩子的节点处理:

求dp(i, 0)时有:

1,将该节点与孩子节点相连,但要保证孩子节点所在的子树种没有黑色节点;

2,将该节点不与该孩子节点相连,则该孩子节点要保证所在子树种有黑色节点;

即dp(i, 0) = π(dp(j,0 ) + dp(j, 1)) ,其中j为i的孩子节点

求dp(i,1)时有:

将该节点与其中每个孩子节点中的一个相连,并且保证该孩子节点所在子树中有1个黑色节点(所以共有K种情况,K为该节点的孩子数),并且对于剩下的节点可以选择连也可以选择不连,如果连接,则保证该子节点所在子树中没有黑色,如果不连,则要保证有黑色,所以对于剩下的每个

子节点的处理方案书有dp(j,0) + dp(j,1)个,然后将每个孩子处理的方案书相乘即可,最后将所有的方案相加即可。

当节点i为黑色的时候,求dp(i, 0) 肯定是0;

求dp(i, 1)时对于i的每个子节点也是有两种选择,连或者不连,如果连接,则保证该子节点所在子树中没有黑色,如果不连,则要保证有黑色,即对于每个子节点的处理数共有

dp(j, 0) + dp(j, 1)个,然后将每个孩子处理的方案数相乘。

最终dp(0,1)即为答案,这里假设0节点为根节点。

过程中可以加个小小的优化,当一个子节点所在的整棵子树中若没有黑色节点,那么该节点肯定与其父节点相连,所以计算时可以不考虑该节点。

#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;
//int values[500001];
//long long sums[500001];
#define MODVALUE 1000000007
#define MOD(x) if((x) > MODVALUE) x %= MODVALUE;

struct Edge
{
	int to;
	int i;
	int totalcolor;
	Edge()
	{
		totalcolor = 0;
	}
};

int compp(const void* a1, const void* a2)
{
	return *((int*)a2) - *((int*)a1);
}

vector<Edge> G[100001];
int Color[100001];
long long res[100001][2];
//int TMP[100001];
bool Visited[100001];

void AddEdge(int from, int to)
{
	Edge edge;
	edge.to = to;

	edge.i = G[to].size();
	G[from].push_back(edge);
	edge.to = from;

	edge.i = G[from].size() - 1;
	G[to].push_back(edge);

}

int CountColor(int node)
{
	Visited[node] = true;
	int count = 0;
	if (Color[node])
	{
		count = 1;
	}
	for (int i = 0; i < G[node].size();i++)
	{
		Edge& edge = G[node][i];
		if (!Visited[edge.to])
		{
			edge.totalcolor = CountColor(edge.to);
			count += edge.totalcolor;
		}

	}
	return count;
}

void GetAns(int node)
{
	Visited[node] = true;
	long long ans = 1;
	int countofcolor = 0;
	vector<int> TMP;
	for (int i = 0; i < G[node].size(); i++)
	{
		Edge& edge = G[node][i];
		if (Visited[edge.to])
		{
			continue;
		}
		//TMP[countofcolor++] = i;
		GetAns(edge.to);
		if (edge.totalcolor)
		{
			TMP.push_back(i);
			countofcolor++;
			//TMP[countofcolor++] = i;
		}
	}
	res[node][0] = 0;
	res[node][1] = 0;

	long long tmp1 = 1;
	long long tmp0 = 1;
	if (!Color[node])
	{
		tmp1 = 0;
	}
	for (int i = 0; i < countofcolor; i++)
	{

		if (Color[node])
		{
			Edge& edge = G[node][TMP[i]];
			tmp1 *= (res[edge.to][1] + res[edge.to][0]);
			MOD(tmp1);
			tmp0 = 0;
		}
		else
		{
			Edge& edge1 = G[node][TMP[i]];
			tmp0 *= (res[edge1.to][1] + res[edge1.to][0]);
			MOD(tmp0);
			long long tmp3 = 1;
			for (int j = 0; j < countofcolor; j++)
			{
				Edge& edge = G[node][TMP[j]];
				if (i == j)
				{
					tmp3 *= res[edge.to][1];
					MOD(tmp3);
				}
				else
				{
					tmp3 *= (res[edge.to][1] + res[edge.to][0]);
					MOD(tmp3);
				}

			}
			tmp1 += tmp3;

		}

		if (i == countofcolor - 1)
		{
			res[node][0] += tmp0;
			res[node][1] += tmp1;
			MOD(res[node][0]);
			MOD(res[node][1]);
		}

	}
	if (countofcolor == 0)
	{
		res[node][0] = Color[node] ? 0 : 1;
		res[node][1] = Color[node] ? 1 : 0;
	}
}

int main()
{
#ifdef _DEBUG
	freopen("e:\\in.txt", "r", stdin);
#endif // _DEBUG
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n - 1; i++)
	{
		int value;
		scanf("%d", &value);
		AddEdge(i + 1, value);
	}
	for (int i = 0; i < n; i++)
	{
		int value;
		scanf("%d", &value);
		Color[i] = value;
	}
	memset(Visited, 0, sizeof(Visited));
	CountColor(0);
	memset(Visited, 0, sizeof(Visited));
	GetAns(0);
	printf("%I64d\n", res[0][1]);
	return 0;
}
时间: 2024-10-12 21:58:53

Codeforces 461B - Appleman and Tree 树状DP的相关文章

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

poj2486--Apple Tree(树状dp)

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7789   Accepted: 2606 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun

Codeforces 461B. Appleman and Tree[树形DP 方案数]

B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are color

CodeForces 461B Appleman and Tree:Tree dp

题目链接:http://codeforces.com/problemset/problem/461/B 题意: 给你一棵树(编号从0到n-1,0为根节点),每个节点有黑白两种颜色,其中黑色节点有k+1个. 现在让你删掉k条边,使得这棵树变成k+1个连通块,并且要保证每个连通块中有且仅有一个黑色节点. 问你删边的方案有多少种. 题解: 表示状态: dp[i][0/1] = numbers 表示在节点i所在的连通块中有(1)或没有(0)黑色节点时,节点i的子树的删边方法数 因为总要保证每个连通块中有

【树形DP】CODEFORCES 461B Appleman and Tree

通道 题意:一棵树上有K个黑色节点,剩余节点都为白色,将其划分成K个子树,使得每棵树上都只有1个黑色节点,共有多少种划分方案 思路:dp[i][0]和dp[i][1]分别表示i子树所在联通块不存在黑节点和已经存在一个黑节点的方案数 代码: #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<ma

codeforces 461B Appleman and Tree

题意:问你将含有黑白点的无向树使得每个子树中只有一个黑点的方法数. 解题思路:树形dp,dp[i][0/1] 表示 第i 个节点的联通图中是否有 1个黑点的种类数. 解题代码: 1 // File Name: 461c.cpp 2 // Author: darkdream 3 // Created Time: 2015年03月11日 星期三 10时53分22秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8

POJ 1155 树状dp

TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3856   Accepted: 2054 Description A TV-network plans to broadcast an important football match. Their network of transmitters and users can be represented as a tree. The root of the tre

POJ 1463 树状dp

Strategic game Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 6629   Accepted: 3058 Description Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad