日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ 2427 软件安装(强连通分量+树形背包)

發布時間:2024/4/17 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 软件安装(强连通分量+树形背包)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。