洛谷P2515[HAOI2021] 软件安装 解题报告!

经典树形背包加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的发表功能,没有什么实际意义,逃。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值