首页 > 其他分享 >洛谷 P2515 软件安装

洛谷 P2515 软件安装

时间:2024-09-04 20:25:59浏览次数:14  
标签:洛谷 P2515 top stk int low sc 软件

洛谷 P2515 软件安装

题意

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

但是现在有个问题:软件之间存在依赖关系,即软件 \(i\) 只有在安装了软件 \(j\)(包括软件 \(j\) 的直接或间接依赖)的情况下才能正确工作(软件 \(i\) 依赖软件 \(j\))。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为 \(0\)。

我们现在知道了软件之间的依赖关系:软件 \(i\) 依赖软件 \(D_i\)。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则 \(D_i=0\),这时只要这个软件安装了,它就能正常工作。

思路

先强连通分量缩点。

如果一个子图互相依赖,要么就全装,要么就全不装。

由于原图每个点入度为 \(1\),是一个外向基环树森林,缩点后为一个森林。

添加超级源点连向每个根节点,然后跑一遍树形背包即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, m, w[N], v[N];
vector <int> E[N];
int low[N], dfn[N], cnt;
bool instk[N];
int stk[N], top, in[N];
int sc, scc[N], W[N], V[N];
int dp[N][N];
bool e[N][N];
void tarjan(int x) {
	low[x] = dfn[x] = ++ cnt;
	stk[++ top] = x; instk[x] = 1;
	for (auto y : E[x]) {
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		} else if (instk[y])
			low[x] = min(low[x], dfn[y]);
	}
	if (low[x] == dfn[x]) {
		sc ++;
		while (top && stk[top] != x) {
			scc[stk[top]] = sc;
			instk[stk[top]] = 0;
			W[sc] += w[stk[top]];
			V[sc] += v[stk[top]];
			top --;
		}
		scc[stk[top]] = sc;
		instk[stk[top]] = 0;
		W[sc] += w[stk[top]];
		V[sc] += v[stk[top]];
		top --;
	}
}
void dfs(int x) {
	dp[x][W[x]] = V[x];
	for (int i = 0; i <= sc; i ++) {
		if (!e[x][i]) continue; 
		dfs(i);
		for (int j = m; j >= W[x]; j --)
			for (int k = 0; k <= j - W[x]; k ++)
				dp[x][j] = max(dp[x][j], dp[x][j - k] + dp[i][k]);
	}
}
int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i ++) cin >> w[i];
	for (int i = 1; i <= n; i ++) cin >> v[i];
	for (int i = 1, d; i <= n; i ++) cin >> d, E[d].push_back(i);
	for (int i = 1; i <= n; i ++) {
		if (dfn[i]) continue;
		tarjan(i);
	}
	for (int i = 1; i <= n; i ++) 
		for (auto j : E[i]) 
			if (scc[i] != scc[j])
				e[scc[i]][scc[j]] = 1,
				in[scc[j]] ++;
	for (int i = 1; i <= sc; i ++) 
		if (!in[i]) e[0][i] = 1;
	dfs(0);
	cout << dp[0][m] << "\n";
	return 0;
} 

标签:洛谷,P2515,top,stk,int,low,sc,软件
From: https://www.cnblogs.com/maniubi/p/18397285

相关文章

  • 洛谷 P3119 Grass Cownoisseur G
    洛谷P3119GrassCownoisseurG题意约翰有\(n\)块草场,编号\(1\)到\(n\),这些草场由若干条单行道相连。奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草。贝西总是从\(1\)号草场出发,最后回到\(1\)号草场。她想经过尽可能多的草场,贝西在通一个草场只吃一次......
  • 洛谷 P9912 Zatopljenje
    洛谷P9912Zatopljenje题意给出长度为\(n\)的序列\(a\),有\(q\)次询问。每次给出\(l,r,x\),询问区间\([l,r]\)中有多少段极长的,\(a\)都大于\(x\)的段。思路离线后扫描线。先把询问和\(a\)离散化,然后扫描\(a\)的值。维护序列\(b\),初始全为\(1\)。扫描从\(......
  • 洛谷 P5340 大中锋的游乐场
    洛谷P5340大中锋的游乐场题意给出一张\(n\)个点\(m\)条边的图,每个点有一个点权\(1\)或\(-1\)。给出点\(s,t\),求出\((s,t)\)间满足以下条件的最短路。任意时刻,走过的路径上点权和均\(\in[-k,k]\)。思路分层图最短路。\(dis_{i,j}\)表示走到\(i\),点权和为\(j......
  • 洛谷 P5618 堵塞的交通
    洛谷P5618堵塞的交通题意有一个\(2\timesC\)的网格图,需要维护\(3\)种操作。连接相邻的两个格子。将相邻的两个格子断开连接。询问两个格子是否联通。思路1考虑分块。连边时块内使用并查集维护,块与块之间用数组标记。删边块内的边时暴力重构并查集,块之间的边清零......
  • 项目管理重点摘要【软考(软件设计师)】
    文章目录前言一、进度管理1.1进度管理的关键步骤1.2工具和方法1.3甘特图1.4关键路径分析法二、风险管理三、成本管理四、沟通管理前言一、进度管理1.1进度管理的关键步骤制定项目或生产计划:管理者需要根据项目或生产的目标、范围、资源等因素,制定出详细的项目或......
  • 2024年最强图纸加密软件大揭秘!图纸加密软件推荐
    在数字化时代,信息安全成为企业发展的重要保障,尤其是对于设计图纸等敏感数据的保护,选择一款可靠的图纸加密软件尤为重要。本文将为您推荐2024年十大图纸加密软件,帮助企业在日常工作中更好地保护知识产权和商业机密。2024年最强图纸加密软件大揭秘!1.固信软件产品功能:固信......
  • Java软件架构师-25个关注点
        Java软件架构师需要掌握的25个关注点,包括微服务、云原生应用、反应式编程和区块链技术等。其中,采用微服务架构是当前Java架构师必须具备的能力之一,因为它能够帮助设计出更加灵活、可扩展和可靠的系统。此外,一些与微服务相关的技术和工具,如SpringBoot、Quarkus和OpenShif......
  • 洛谷 B3645 数列前缀和 2 题解
    前缀知识:枚举,费马小定理,逆元,线性乘法逆元,线段树(?)。解法1:暴力如题。暴力枚举即可,30分。由于太简单,不给代码。解法2:前缀积+费马小定理+逆元由于涉及静态区间,可以想到前缀积。前缀积公式为\(q_r/q_{l-1}\),除法恰好可以用逆元来算。直接写即可。不会超时,因为时间为\(O(n\logp)\)......
  • Altium designer软件介绍
    AltiumDesigner是原Protel软件开发商Altium公司推出的一体化的电子产品开发系统,主要运行在Windows操作系统。这套软件通过把原理图设计、电路仿真、PCB绘制编辑、拓扑逻辑自动布线、信号完整性分析和设计输出等技术的完美融合,为设计者提供了全新的设计解决方案,使设计者可以轻松......
  • 自我认知及软件工程学习指南
    目前我已经具备的专业知识:数据库、数据挖掘、机器学习、c、python、matlab等,会使用pytorch、tensorflow基础功能,了解深度学习的基础算法。会使用神经网络、森林灭火等数学建模常用算法我感兴趣的技术方向:联邦学习、大数据架构、跨学科领域交叉数据融合分析、大数据治理等我缺少......