当前位置: 首页 > news >正文

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; }



相关文章:

  • Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】
  • MyBatis学习总结(11)——MyBatis动态Sql语句
  • Android应用正确使用扩展SD卡,特别是安卓4.4以后的版本
  • 开源HYBUnicodeReadable日志显示Unicode中文
  • CKEditor在线编辑器增加一个自定义插件
  • 【转载】Tomcat 7.0.3x 启动慢并且遇到StackOverflowError的异常的解决办
  • ubuntu14.04 使用kvm安装win7系统
  • A successful Git branching model
  • ELK日志系统:Elasticsearch + Logstash + Kibana 搭建教程
  • centos制作yum源
  • android在假设绘制自己定义的bitmap,然后返回给ImageView
  • 通过读取excel文件生成sql语句
  • 指针知识梳理5-字符串与指针,程序内存总结
  • 使用360浏览器访问字体逆时针旋转90度的问题
  • Shell脚本实现自动修改IP地址
  • [译]CSS 居中(Center)方法大合集
  • 【css3】浏览器内核及其兼容性
  • JS基础之数据类型、对象、原型、原型链、继承
  • LintCode 31. partitionArray 数组划分
  • react-native 安卓真机环境搭建
  • Redis 懒删除(lazy free)简史
  • spring学习第二天
  • uni-app项目数字滚动
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • vue2.0项目引入element-ui
  • vue-router 实现分析
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 如何设计一个微型分布式架构?
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 数据结构java版之冒泡排序及优化
  • 算法-图和图算法
  • 算法之不定期更新(一)(2018-04-12)
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • Python 之网络式编程
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​LeetCode解法汇总518. 零钱兑换 II
  • #if和#ifdef区别
  • $L^p$ 调和函数恒为零
  • (06)Hive——正则表达式
  • (1)(1.13) SiK无线电高级配置(五)
  • (52)只出现一次的数字III
  • (分布式缓存)Redis持久化
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • ./configure,make,make install的作用
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET 的程序集加载上下文
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...