【題目描述】
現在我們的手頭有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
【樣例輸出】
5【題意分析】
給你一堆軟體,每個軟體有重量和價值,而且有乙個依賴物件,裝了依賴物件才能裝當前這個。
蒟蒻剛拿到這道題——這不裸的樹上揹包動規嗎?於是暴力從沒有依賴的軟體(看做根節點)打了個樹形dp,還過樣例了。
於是自信滿滿地點了一下標籤——縮點??!!
恍然大悟——哦!題目沒說這是一棵樹。。。
因此可能會存在多個環。我們想一下——乙個環裡的軟體肯定是要麼全裝,要麼全不裝。那麼我們就把乙個環打包起來。。。成乙個節點。剩下的就是乙個dag圖(有向無環圖),在這個dag圖上進行樹形動規。
那麼這些環將何去何從?把它們連到那裡去?可以想一下,一旦撞到環了,肯定就不能往更深的地方下去了,因為它們忙著互相依賴,哪有功夫再往深的地方鑽?那麼我們就用簡單暴力點的方法:弄乙個虛擬節點0,把環和森林的根節點全都連到虛擬節點上面去。然後從虛擬節點開始樹形dp。
樹上揹包問題:設dp[
i][j
dp[i][j
dp[i][
j]表示目前到i節點,花費j容量獲得的最大價值。那麼dp[
i][j
+w[i
]]=m
ax(d
p[i]
[j+w
[i]]
,dp[
i][j
+w[i
]−k]
+dp[
v][k
]dp[i][j+w[i]]=max(dp[i][j+w[i]],dp[i][j+w[i]-k]+dp[v][k]
dp[i][
j+w[
i]]=
max(
dp[i
][j+
w[i]
],dp
[i][
j+w[
i]−k
]+dp
[v][
k]其中w[i]是當前這個節點的重量,v是列舉的每個子節點,k取遍0到j。
重新建圖的時候原來的東西要清零~
code:
#include#include#include#include#include#define max 1000
using namespace std;
struct front_link_staredge[max];
stack s;
int head[max],w[max],v[max],w[max],v[max],dag[max];
int dfn[max],low[max],indegree[max],n,m,tot_circle,cnt,tag;
int dp[max][max];
bool vis[max],check[max][max];
inline void add_edge(int u,int v)
inline int read()
while (isdigit(ch))
return s*w;
}inline void tarjan(int now)else if (vis[v])low[now]=min(low[now],low[v]);
} if (dfn[now]==low[now])while (now!=y);
}} //縮點
inline void dp(int now) //暴力dp
}int main()
for (register int i=1;i<=n;i++)
if (!dfn[i])tarjan(i); //縮點
for (register int i=1;i<=n;i++) //判斷是否是環。
}}
//重新建圖。
//本來可以直接add_edge(i,j),因為會對圖造成影響,所以弄乙個判斷陣列。
cnt=0;
memset(edge,0,sizeof(edge));
memset(head,0,sizeof(head));
//清零別忘了。
for (register int i=1;i<=tot_circle;i++)
for (register int j=1;j<=tot_circle;j++)
if (check[i][j])add_edge(i,j);
for (register int i=1;i<=tot_circle;i++)
if (!indegree[i])add_edge(0,i);
//瘋狂連邊
dp(0); //從虛擬節點開始dp
printf("%d",dp[0][m]); //dp[0][m]為答案
return 0;
}
HAOI2010 軟體安裝
現在我們的手頭有n個軟體,對於乙個軟體i,它要占用wi的磁碟空間,它的價值為vi。我們希望從中選擇一些軟體安裝到一台磁碟容量為m計算機上,使得這些軟體的價值盡可能大 即vi的和最大 但是現在有個問題 軟體之間存在依賴關係,即軟體i只有在安裝了軟體j 包括軟體j的直接或間接依賴 的情況下才能正確工作 ...
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...