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(缩点+有依赖的树形背包)的更多相关文章

  1. 一类有依赖的树形背包dp方法

    失踪人口回归系列 这个标题是不是看起来很厉害呢233 给一道例题:有一个树,每一个节点代表一个物品,每个物品有重量和价值,每个物品必须先选父亲才能选自己.求给定重量内最大价值. 这题的思路十分的厉害. ...

  2. 【洛谷 P2515】 [HAOI2010]软件安装 (缩点+树形背包)

    题目链接 看到代价和价值这两个关键词,肯定是首先要想到背包的. 但是图中并没有说这是棵树,所以先要\(Tarjan\)缩点,然后就是选课了,跑一遍树形背包就好了. 注意:缩点后应该是一个森林,应该用一 ...

  3. 洛谷 P1064 金明的预算方案【有依赖的分组背包】

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱 ...

  4. We Need More Bosses CodeForces - 1000E (无向图缩点)

    大意: 给定无向连通图, 定义两个点$s,t$个价值为切断一条边可以使$s,t$不连通的边数. 求最大价值. 显然只有桥会产生贡献. 先对边双连通分量缩点建树, 然后求直径即为答案. #include ...

  5. Cactus CodeForces - 231E (无向图缩环)

    大意: 给定无向图, 每个点最多属于一个简单环, 多组询问, 求给定起点终点, 有多少条简单路径. 先缩环, 然后假设两点树上路径经过$cnt$个环, 那么答案就为$2^{cnt}$. 要注意缩环建树 ...

  6. We Need More Bosses CodeForces - 1000E(缩点 建图 求桥 求直径)

    题意: 就是求桥最多的一条路 解析: 先求连通分量的个数 然后缩点建图  求直径即可 #include <bits/stdc++.h> #define mem(a, b) memset(a ...

  7. [HAOI2010]软件安装(树形背包,tarjan缩点)

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

  8. Codeforces 743D:Chloe and pleasant prizes(树形DP)

    http://codeforces.com/problemset/problem/743/D 题意:求最大两个的不相交子树的点权和,如果没有两个不相交子树,那么输出Impossible. 思路:之前好 ...

  9. HDu 3449 (有依赖的01背包) Consumer

    题意: 有n件物品,对应有不同的价格和价值,这是典型的01背包.但现在有了一个限制,要买物品先买能装这件物品的特定的盒子,盒子的价值为0 代码理解得还不是太好,感觉这是一个“二重”的01背包.首先假设 ...

随机推荐

  1. QT实现鼠标钩子(使用SetWindowsHookEx安装mouseProc函数)

    HHOOK mouseHook=NULL; LRESULT CALLBACK mouseProc(int nCode,WPARAM wParam,LPARAM lParam ) { if(nCode ...

  2. Template简介

    分类   ControlTemplate ItemsPanelTemplate DataTemplate 样式Style和模板Template对比 Style:样式,风格Template:模版,某种控 ...

  3. js 评分

    <!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...

  4. Sql 执行查询顺序

  5. WPF 创建无边框的圆角窗口

    原文:WPF 创建无边框的圆角窗口 如题所述,在WPF中要创建一个没有边框且为圆角的窗体,有如下几步工作要进行: 第一步:去掉窗体默认样式的边框 首先将窗体的背景设为透明,将允许透明的属性设置为Tru ...

  6. python 识别身份证号码

    # !/usr/bin/python # -*-coding:utf-8-*- import sys import time time1 = time.time() from PIL import I ...

  7. python socket 客服端服务端编程

    客服端编程 import socket try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error a ...

  8. Visual Studio 2015 和 Apache Cordova 跨平台开发入门

    原文:Visual Studio 2015 和 Apache Cordova 跨平台开发入门(一) 基于 Windows 10 的 Visual Studio 2015 跨平台的应用开发主要分为基于V ...

  9. Image Caption论文合辑2

    说明: 这个合辑里面的论文不全是Image Caption, 但大多和Image Caption相关, 同时还有一些Workshop论文. Guiding Long-Short Term Memory ...

  10. swift 如何控制view的显示与隐藏

    swift 如何控制view的显示与隐藏 UIView有一个属性 hidden let line: UILabel = UILabel() 默认是显示的 需要显示它的时候:line.hidden = ...