Codeforces Gym100502G:Outing(缩点+有依赖的树形背包)
http://codeforces.com/gym/100502/attachments
题意:有n个点,容量为tol,接下来n个关系,表示选了第i个点,那么第xi个点就必须被选。问最多可以选多少个点使得不超过容量tol。
思路:由题目样例可得,边可能出现自环的情况,这个时候这条边其实没用。然后因为是一个图,所以需要缩点,缩完之后用一个sz数组表示点的大小,重新建一幅图。因为有可能是森林,所以需要添加一个虚根,使得其变成一棵树。然后题目就转变为求有依赖的树上背包了。
我是学了这篇博客的写法:http://blog.csdn.net/y990041769/article/details/38068223
dp[i][j]表示以i为根的子树在容量为j的时候能放的点的最大个数。sz[i]表示i结点的大小。
因为i是必须选的(不然其儿子都没办法选),那么一开始就直接赋予其值。
for(int j = tol; j >= sz[u]; j--) { // 枚举容量
for(int k = ; k <= j - sz[u]; k++) { // k表示能分配给子节点的容量
dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]);
}
}
接下来第一层循环是像01背包一样,枚举能够放下u(根结点)自己的容量,第二层循环k代表能够分配给儿子的容量,因为根结点自己已经放进去了,所以是j-sz[u]。就这样可以更新完u这个根节点了。
#include <bits/stdc++.h>
using namespace std;
#define N 1010
struct Edge {
int v, nxt;
} edge[N*], e[N*];
int n, tol, head[N], tot, h[N], t, dfn[N], low[N], belong[N], vis[N], num, tid, sz[N], deg[N], dp[N][N];
stack<int> sta; void Add(int u, int v) { edge[tot] = (Edge) {v, head[u]}; head[u] = tot++; }
void add(int u, int v) { e[t] = (Edge) {v, h[u]}; h[u] = t++; } void tarjan(int u) {
sta.push(u);
vis[u] = ;
dfn[u] = low[u] = ++tid;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(vis[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
num++;
int top = -;
while(top != u) {
top = sta.top(); sta.pop();
belong[top] = num;
sz[num]++;
vis[top] = ;
}
}
} void BuildGraph() {
memset(head, -, sizeof(head));
memset(h, -, sizeof(h));
t = tot = ;
for(int i = ; i <= n; i++) {
int j; scanf("%d", &j);
if(i == j) continue;
Add(j, i);
}
for(int i = ; i <= n; i++)
if(!dfn[i]) tarjan(i); // 将环缩点重新建图
for(int u = ; u <= n; u++) {
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(belong[u] != belong[v]) {
add(belong[u], belong[v]);
deg[belong[v]]++;
}
}
}
for(int i = ; i <= num; i++) // 设一个虚根将森林变成树
if(!deg[i]) add(, i);
} void dfs(int u) {
for(int i = tol; i >= sz[u]; i--) dp[u][i] = sz[u]; // 初始状态必须有这个结点的sz
for(int i = h[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
dfs(v);
for(int j = tol; j >= sz[u]; j--) { // 枚举容量
for(int k = ; k <= j - sz[u]; k++) { // k表示能分配给子节点的容量
dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]);
}
}
}
} void Bag() {
dfs();
printf("%d\n", dp[][tol]);
} int main() {
scanf("%d%d", &n, &tol);
BuildGraph();
Bag();
return ;
}
Codeforces Gym100502G:Outing(缩点+有依赖的树形背包)的更多相关文章
- 一类有依赖的树形背包dp方法
失踪人口回归系列 这个标题是不是看起来很厉害呢233 给一道例题:有一个树,每一个节点代表一个物品,每个物品有重量和价值,每个物品必须先选父亲才能选自己.求给定重量内最大价值. 这题的思路十分的厉害. ...
- 【洛谷 P2515】 [HAOI2010]软件安装 (缩点+树形背包)
题目链接 看到代价和价值这两个关键词,肯定是首先要想到背包的. 但是图中并没有说这是棵树,所以先要\(Tarjan\)缩点,然后就是选课了,跑一遍树形背包就好了. 注意:缩点后应该是一个森林,应该用一 ...
- 洛谷 P1064 金明的预算方案【有依赖的分组背包】
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱 ...
- We Need More Bosses CodeForces - 1000E (无向图缩点)
大意: 给定无向连通图, 定义两个点$s,t$个价值为切断一条边可以使$s,t$不连通的边数. 求最大价值. 显然只有桥会产生贡献. 先对边双连通分量缩点建树, 然后求直径即为答案. #include ...
- Cactus CodeForces - 231E (无向图缩环)
大意: 给定无向图, 每个点最多属于一个简单环, 多组询问, 求给定起点终点, 有多少条简单路径. 先缩环, 然后假设两点树上路径经过$cnt$个环, 那么答案就为$2^{cnt}$. 要注意缩环建树 ...
- We Need More Bosses CodeForces - 1000E(缩点 建图 求桥 求直径)
题意: 就是求桥最多的一条路 解析: 先求连通分量的个数 然后缩点建图 求直径即可 #include <bits/stdc++.h> #define mem(a, b) memset(a ...
- [HAOI2010]软件安装(树形背包,tarjan缩点)
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- Codeforces 743D:Chloe and pleasant prizes(树形DP)
http://codeforces.com/problemset/problem/743/D 题意:求最大两个的不相交子树的点权和,如果没有两个不相交子树,那么输出Impossible. 思路:之前好 ...
- HDu 3449 (有依赖的01背包) Consumer
题意: 有n件物品,对应有不同的价格和价值,这是典型的01背包.但现在有了一个限制,要买物品先买能装这件物品的特定的盒子,盒子的价值为0 代码理解得还不是太好,感觉这是一个“二重”的01背包.首先假设 ...
随机推荐
- PD生成兼容Oracle、Mysql脚本
mysql date 改为 datetime ->运行sql脚本 Oracle " clustered " 替换为空,即key(XX) ->运行sql脚本
- 基于Linux C的socketEthereal程序和Package分析 (一个)
执行测试平台:CentOS 6.5发行版,内核版本号3.11 1. Linux抓包源程序 在OSI七层模型中.网卡工作在物理层和数据链路层的MAC子层. 进行网络通信时.源主机通过socket( ...
- WPF的Timer控件的使用
原文:WPF的Timer控件的使用 通过System.Threaing.Timer控件来实现“初始加载页面时为DataGrid的模版列赋初始值” System.Threaing.Timer的用法: 步 ...
- 新秀翻译(一个)——Java在继承和组合
阅读英文的程序猿的能力,这是非常重要的.过去的几年中一直在学习英语,今天心血来潮,在网上找什么鲍文简要翻译. 普通级,能力有限,看官还请大家多多指点. 译文: 本文将会举例说明Java中继承和组合的概 ...
- Base64实现测试,不要太相信apache-common的性能
针对三种Base64实现: * 自已实现的 * JDK8的java.util.Base64 * apache-common的org.apache.commons.codec.binary.Base64 ...
- COM编程基础(C++)
转自:http://www.yesky.com/20020715/1620482_1.shtml (作为一个初学者,觉得本文挺好,推荐给大家) 这篇文章是给初学者看的,尽量写得比较通俗易懂,并且尽量避 ...
- C++调用Python浅析
环境 VS2005Python2.5.4 Windows XP SP3 简述 一般开发过游戏的都知道Lua和C++可以很好的结合在一起,取长补短,把Lua脚本当成类似动态链接库来使用,很好的利用了脚本 ...
- delphi 线程教学第一节:初识多线程(讲的比较浅显),还有三个例子
http://www.cnblogs.com/lackey/p/6297115.html 几个例子: http://www.cnblogs.com/lackey/p/5371544.html
- golang生成c-shared so供c语言或者golang调用到例子
1.golang生成c-shared类型到so 建立文件夹hello,创建main.go文件,内容如下 package main import "C" func main() {} ...
- UWP ListView
ListViewItem项填充整个宽度最大化<ListView.ItemContainerStyle> <Style TargetType="ListViewItem&qu ...