经典树形背包加Tarjan缩点
题目就不重述了,下面有链接。在我们学会Tarjan缩点和树形背包后几乎就是模板题了。
这是一个小链接
代码如下:
#pragma warning(disable:4996)//VS的毛病
#include<stdio.h>
#include<queue>
#include<stdbool.h>
#include<cstring>
#define max(a, b) (a > b ? a : b)
#define min(a, b) (a < b ? a : b)
#define mem(a, sum) memset(a, sum, sizeof a)
typedef long long int ll;
const int MAXn = 105, MAXm = 505;
//快读
int read() {
int w = 0, r = 0; char ch = getchar();
while (ch < '0' || ch >'9')w |= ch == '-', ch = getchar();
while (ch >= '0' && ch <= '9')
r = (r << 1) + (r << 3) + (ch ^ 48), ch = getchar();
return w ? ~r + 1 : r;
}
int n, m, v1[MAXn], w1[MAXn];
//前向星
int head[MAXn], cnt;
struct Edge {
int u, v, next;
}ed[MAXn];
void add(int u, int v){
ed[++cnt].u = u;
ed[cnt].v = v;
ed[cnt].next = head[u];
head[u] = cnt;
return;
}
int dfn[MAXn], low[MAXn], id;
int sta[MAXn], top, col[MAXn], color;
bool vis[MAXn];
void Tarjan(int x) {
dfn[x] = low[x] = ++id;
sta[++top] = x; vis[x] = true;
for (int i = head[x]; i; i = ed[i].next) {
int v = ed[i].v;
if (dfn[v] == 0) {
Tarjan(v);
low[x] = min(low[x], low[v]);
}
else if (vis[v]) {
low[x] = min(low[x], dfn[v]);
}
}
if (dfn[x] == low[x]) {
col[x] = ++color;
while (sta[top] != x) {
int p = sta[top--];
vis[p] = false;
col[p] = color;
}
top--;
vis[x] = false;
}
return;
}
int hea2[MAXn], cn2, indg[MAXn], v2[MAXn], w2[MAXn];
struct Edg {
int u, v, next;
}ed2[MAXn];
void add2(int u, int v) {
ed2[++cn2].u = u;
ed2[cn2].v = v;
ed2[cn2].next = hea2[u];
hea2[u] = cn2;
indg[v]++;
return;
}
//建个新图
void Mapping() {
for (int i = 1; i <= n; i++) {
v2[col[i]] += v1[i];
w2[col[i]] += w1[i];
}
for (int i = 1; i <= cnt; i++) {
int u = ed[i].u, v = ed[i].v;
if (col[u] == col[v]) {
}
else {
add2(col[u], col[v]);
}
}
//连上0号点
for (int i = 1; i <= color; i++) {
if (indg[i] == 0) {
add2(0, i);
}
}
return;
}
//树形依赖背包
int dp[MAXn][MAXm];
void dfs(int u, int tot) {
if (tot <= 0)return;
for (int i = hea2[u]; i; i = ed2[i].next) {
int v = ed2[i].v;
for (int j = 0; j <= tot - w2[v]; j++) {
dp[v][j] = dp[u][j];
}
dfs(v, tot - w2[v]);
for (int j = tot; j >= w2[v] ; j--) {
dp[u][j] = max(dp[u][j], dp[v][j - w2[v]] + v2[v]);
}
}
return;
}
//检查一下
void checkout() {
for (int i = 1; i <= n; i++) {
printf("原图 点 %d 容量 %d 价值 %d\n", i, w1[i], v1[i]);
}
for (int i = 1; i <= cnt; i++) {
printf("原边%d %d\n", ed[i].u, ed[i].v);
}
for (int i = 1; i <= cn2; i++) {
printf("新边 %d %d \n", ed2[i].u, ed2[i].v);
}
for (int i = 1; i <= color; i++) {
printf("新点 %d %d %d\n", i, w2[i], v2[i]);
}
for (int i = 0; i <= n; i++) {
printf("dp %d: ", i);
for (int j = m; j >= 0; j--) {
printf("%d ", dp[i][j]);
}printf("\n");
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
n = read(); m = read();
for (int i = 1; i <= n; i++) {
w1[i] = read();
}
for (int i = 1; i <= n; i++) {
v1[i] = read();
}
for (int i = 1; i <= n; i++){
int p = read();
if (p != 0) {
add(p, i);
}
}
for (int i = 1; i <= n; i++) {
if (dfn[i] == 0)Tarjan(i);
}
Mapping();
dfs(0, m);
//checkout();
printf("%d ", dp[0][m]);
return 0;
}
这篇文章主要是试验一下CSDN的发表功能,没有什么实际意义,逃。