bzoj3090
树形dp
有一个比较明显的dp状态是dp[i][j]表示当前i节点的子树已经满足且i剩下j元钱的最小操作次数,这样复杂度比较高状态数已经有O(n*x)的了,转移再来x,肯定不行。
我们考虑把状态和dp值交换一下,因为操作次数最多只有n-1次,这样可以大大降低dp状态数,于是我们设dp[i][j]表示i的子树已经满足了,且操作了j次,根节点最多能有多少多余的钱,这里可以是负数,我们自然希望子树内满足之后,根节点钱尽量多,这样可以支持其他节点,转移就是背包dp,tmp[i+j+1]=min(tmp[i+j+1],dp[u][i]+dp[v][j]),表示我们把v的钱转移到u上,那么这样又进行了一次操作,如果dp[u][j]>=0,说明u节点满足了,那么我们可以不用子树来支持,那么tmp[i+j]=min(tmp[i+j],dp[u][j]),这样是说不转移,然后那么v上的钱就不可能转移上来了,最后答案就是dp[1][j]>=0的j。
如果状态过多,有时我们可以考虑交换状态和dp值,这样可以降低复杂度
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = ;
int n, X;
vector<int> G[N];
int dp[N][N], tmp[N], v[N], size[N];
void dfs(int u, int last)
{
size[u] = ;
// for(int i = 0; i <= n; ++i) dp[u][i] = X - v[u];
dp[u][] = X - v[u];
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if(v == last) continue;
dfs(v, u);
memset(tmp, -0x3f3f, sizeof(tmp));
for(int j = ; j <= size[u]; ++j)
for(int k = ; k <= size[v]; ++k)
{
tmp[j + k + ] = max(tmp[j + k + ], dp[u][j] + dp[v][k]);
if(dp[v][k] >= ) tmp[j + k] = max(tmp[j + k], dp[u][j]);
}
size[u] += size[v];
for(int j = ; j <= size[u] + ; ++j) dp[u][j] = tmp[j];
}
}
int main()
{
scanf("%d%d", &n, &X);
for(int i = ; i <= n; ++i) scanf("%d", &v[i]);
for(int i = ; i < n; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(dp, -0x3f3f, sizeof(dp));
dfs(, );
for(int i = ; i < n; ++i) if(dp[][i] >= )
{
printf("%d\n", i);
return ;
}
return ;
}
bzoj3090的更多相关文章
- bzoj3090: Coci2009 [podjela]
这个范围明显树包的 然而值并不滋磁 想了一会发现可以带一维当前子树用了多少边,搞定当前向上还能送多少 然后发现会有搞不定的情况,要向上传负数 每次都要重新初始化,负数强制要要 #include< ...
随机推荐
- [luoguP1169] [ZJOI2007]棋盘制作(单调栈)
传送门 和玉蟾宫差不多 ——代码 #include <cstdio> #include <iostream> using namespace std; ; int n, m, ...
- [转]制作一个64M的U盘启动盘(mini linux + winpe +dos toolbox)
自己动手定制winpe+各类dos工具箱U盘启动盘+minilinux 由于一个64M老U盘,没什么用,拿来发挥余热.如果U盘够大,可以使用功能更强大的mini linux和带更多工具的winpe.这 ...
- BZOJ1583: [Usaco2009 Mar]Moon Mooing 哞哞叫
给n<=4000000,c,a1,b1,c1,a2,b2,c2,以c为初始得到的数,每次可以把得到的某个数x进行操作f1(x)=a1*x/c1+b1,f2(x)=a2*x/c2+b2,求最后能得 ...
- Linux中的进程与线程
介绍了Linux下fork()创建进程以及使用pthread_create()创建线程的方法 1. 基于进程的斐波那契数列 在下面的代码中,由子进程进行斐波那契数列的输出,父进程要等待子进程输出完毕, ...
- 洛谷——P2256 一中校运会之百米跑
P2256 一中校运会之百米跑 题目背景 在一大堆秀恩爱的**之中,来不及秀恩爱的苏大学神踏着坚定(?)的步伐走向了100米跑的起点.这时苏大学神发现,百米赛跑的参赛同学实在是太多了,连体育老师也忙不 ...
- Linux下使用Curl调用Java的WebService接口
其实只要是标准的WSDL的SOA接口WebService都可以用. 调用方式: 注意:上面的方式不包括加密或者登录的,其实SOA有一套完整的加密方式. curl -H'Content-Type: te ...
- Spring MVC的Hello World例子
以下内容引用自http://wiki.jikexueyuan.com/project/spring/mvc-framework/spring-mvc-hello-world-example.html: ...
- php monolog 的写日志到unix domain socket 测试终于成功
在另外一个客户端执行 php s.php后, 通过nc -lU /tmp/tg.sck 建立的unix domain socket 有接收到消息. <?php require 'vendor/a ...
- Ansible 详细用法说明(一)
一.概述 运维工具按需不需要有代理程序来划分的话分两类: agent(需要有代理工具):基于专用的agent程序完成管理功能,puppet, func, zabbix agentless(无须代理工具 ...
- HTML的DIV如何实现垂直居中
外部的DIV必须有如下代码 display:table-cell; vertical-align:middle; 这样可以保证里面的东西,无论是DIV还是文本都可以垂直居中