現在我們的手頭有n個軟體,對於乙個軟體i,它要占用wi的磁碟空間,它的價值為vi。我們希望從中選擇一些軟體安裝到一台磁碟容量為m計算機上,使得這些軟體的價值盡可能大(即vi的和最大)。
但是現在有個問題:軟體之間存在依賴關係,即軟體i只有在安裝了軟體j(包括軟體j的直接或間接依賴)的情況下才能正確工作(軟體i依賴軟體j)。幸運的是,乙個軟體最多依賴另外乙個軟體。如果乙個軟體不能正常工作,那麼它能夠發揮的作用為0。
我們現在知道了軟體之間的依賴關係:軟體i依賴軟體di。現在請你設計出一種方案,安裝價值盡量大的軟體。乙個軟體只能被安裝一次,如果乙個軟體沒有依賴則di=0,這時只要這個軟體安裝了,它就能正常工作。
第1行:n, m (0<=n<=100, 0<=m<=500)
第2行:w1, w2, … wi, …, wn (0<=wi<=m )
第3行:v1, v2, …, vi, …, vn (0<=vi<=1000 )
第4行:d1, d2, …, di, …, dn (0<=di<=n, di≠i )
乙個整數,代表最大價值
3 10
5 5 6
2 3 4
0 1 1
思路:強連通分量+樹形 dp 。
對於每個 i,從 i 向 di 建一條有向邊。
由於依賴關係可以形成環,裡面的節點要麼都選,要麼都不選。
所以,先縮點,構成乙個新圖,這樣新圖里的每個節點可以看成乙個新圖。建乙個0節點,向新圖里所有的入度為 0 的節點建一條有向邊,構成一棵樹,以0節點作為根。
建樹完畢後,在構成的樹上做 dp 。
以下 cost[i] 和 val[i] 分別為樹上每個節點的費用和價值,設 f[u][i] 為在節點 u 的子樹內,費用限制為 i 的條件下能取到的最大價值。
類似洛谷p2014選課
最後答案為 f[
0][m
] f[0
][m]
。
#include
#include
#include
#include
#include
using
namespace
std;
const
int n = 105, m = 505;
int n, m, w[n], v[n], f[n][m];
int ecnt, nxt[m], adj[n], go[m], top;
int sta[n], dfn[n], low[n], times;
int num, bel[n], cost[n], val[n], ecnt2;
int nxt2[m], adj2[n], go2[m], d[n];
bool ins[n], g[n][n];
void add_edge(int u, int v)
void add_edge2(int u, int v)
void tarjan(int u)
else
if (ins[v]) low[u] = min(low[u], dfn[v]);
if (dfn[u] == low[u])
}void dp(int u)
}int main()
for (i = 1; i <= num; i++)
for (j = 1; j <= num; j++)
if (g[i][j]) add_edge2(i, j);
for (i = 1; i <= num; i++)
if (!d[i])
add_edge2(num + 1, i);
printf("%d\n", (dp(num + 1), f[num + 1][m]));
}
HAOI2010 軟體安裝
現在我們的手頭有n個軟體,對於乙個軟體i,它要占用wi的磁碟空間,它的價值為vi。我們希望從中選擇一些軟體安裝到一台磁碟容量為m計算機上,使得這些軟體的價值盡可能大 即vi的和最大 但是現在有個問題 軟體之間存在依賴關係,即軟體i只有在安裝了軟體j 包括軟體j的直接或間接依賴 的情況下才能正確工作 ...
HAOI2010 軟體安裝
開始沒有看懂題,以為就是個樹形依賴揹包,打完之後w40,然後才發現它會有還,要用tarjan縮完點後跑揹包,要建立乙個虛擬節點0連線所有的子圖 注意連線的位置 錯誤示範 1 for int i 1 i n i 這樣會導致0連線的不是入度為0的點 或環 2if dsn i 3 正確 1 for int...
HAOI2010 軟體安裝
傳送門 一開始我以為這道題是乙個比較正常的分組揹包,只不過原來做的題目的限制條件是數目,這次是有體積 軟體所佔空間 的限制,但是兩者好像沒什麼差異 於是我就仿著正常的分組揹包寫了一下,然後過了樣例。我才不會告訴你我一開始結果全是0,因為我寫錯了 交上去一看只有10分 回來發現原來這題並沒有說是一棵樹...