生活随笔
收集整理的這篇文章主要介紹了
BZOJ 2427 软件安装(强连通分量+树形背包)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:現在我們的手頭有N個軟件,對于一個軟件i,它要占用Wi的磁盤空間,它的價值為Vi。我們希望從中選擇一些軟件安裝到一臺磁盤容量為M計算機上,使得這些軟件的價值盡可能大(即Vi的和最大)。
但是現在有個問題:軟件之間存在依賴關系,即軟件i只有在安裝了軟件j(包括軟件j的直接或間接依賴)的情況下才能正確工作(軟件i依賴軟件j)。幸運的是,一個軟件最多依賴另外一個軟件。如果一個軟件不能正常工作,那么它能夠發揮的作用為0。
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <
set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-
x))
# define pi acos(-
1.0)
# define eps 1e-
8
# define MOD 2007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(
int i=a; i<=n; ++
i)
# define FO(i,a,n) for(
int i=a; i<n; ++
i)
# define bug puts("H");
# define lch p<<
1,l,mid
# define rch p<<
1|
1,mid+
1,r
# define mp make_pair
# define pb push_back
typedef pair<
int,
int>
PII;
typedef vector<
int>
VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {int x=
0,f=
1;
char ch=
getchar();while(ch<
'0'||ch>
'9'){
if(ch==
'-')f=-
1;ch=
getchar();}while(ch>=
'0'&&ch<=
'9'){x=x*
10+ch-
'0';ch=
getchar();}return x*
f;
}
const int N=
105;
//Code begin...struct Edge{
int p, next;}edge[N];
int head[N], cnt=
1;
int W[N], V[N], D[N], cost[N], val[N], dp[N][
505], m;
int Low[N], DFN[N], Stack[N], Belong[N], dee[N], Index, top, scc;
bool Instack[N], vis[N][N];
VI E[N];void add_edge(
int u,
int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++
;}
void Tarjan(
int u){int v;Low[u]=DFN[u]=++Index; Stack[top++]=u; Instack[u]=
true;for (
int i=head[u]; i; i=
edge[i].next) {v=
edge[i].p;if (!
DFN[v]) {Tarjan(v);if (Low[u]>Low[v]) Low[u]=
Low[v];}else if (Instack[v]&&Low[u]>DFN[v]) Low[u]=
DFN[v];}if (Low[u]==
DFN[u]) {++
scc;do{v=Stack[--top]; Instack[v]=
false; Belong[v]=scc; cost[scc]+=W[v]; val[scc]+=
V[v];}while (v!=
u);}
}
void solve(
int n){mem(DFN,0); mem(Instack,
false); Index=scc=top=
0;FOR(i,1,n)
if (!
DFN[i]) Tarjan(i);
}
void dfs(
int x){FO(i,0,E[x].size()) {int v=
E[x][i];dfs(v);for (
int j=m; j>=
0; --j) FOR(k,cost[v],j) dp[x][j]=max(dp[x][j],dp[x][j-k]+
dp[v][k]);}for (
int i=m; i>=cost[x]; --i) dp[x][i]=dp[x][i-cost[x]]+
val[x];
}
int main ()
{int n;scanf("%d%d",&n,&
m);FOR(i,1,n) scanf(
"%d",W+
i);FOR(i,1,n) scanf(
"%d",V+
i);FOR(i,1,n) {scanf("%d",D+
i);if (D[i]) add_edge(D[i],i);}solve(n);FOR(i,1,n) {int u=
Belong[i];for (
int j=head[i]; j; j=
edge[j].next) {int v=
Belong[edge[j].p];if (u==v||vis[u][v])
continue;E[u].pb(v); vis[u][v]=
true; ++
dee[v];}}FOR(i,1,scc)
if (!dee[i]) E[
0].pb(i);dfs(0);printf("%d\n",dp[
0][m]);return 0;
} View Code ?
我們現在知道了軟件之間的依賴關系:軟件i依賴軟件Di?,F在請你設計出一種方案,安裝價值盡量大的軟件。一個軟件只能被安裝一次,如果一個軟件沒有依賴則Di=0,這時只要這個軟件安裝了,它就能正常工作。
依照依賴關系可以建一個圖,這個圖中每個點的入度至多1,不難發現,這是一些環加上樹組成的森林,對于環,要么不選要么都選,于是可以把環縮點。
這樣原圖就變成了一個有向森林,對于每個根節點,我們建立一個虛擬節點連向這些節點,于是就變成了一顆樹。
在樹上做樹形依賴背包即可,定義dp[x][v]表示x的子樹占用了v的內存能產生的最大價值。轉移方程很簡單。
時間復雜度O(n^2*m).
?
轉載于:https://www.cnblogs.com/lishiyao/p/6933443.html
總結
以上是生活随笔為你收集整理的BZOJ 2427 软件安装(强连通分量+树形背包)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。