[BZOJ]2427: [HAOI2010]软件安装
题解: 树上背包合并裸题 需要考虑有环 所以缩环成一个点 这点的价值等于环上所有点的价值和
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=105;
const int NM=505;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int f[MAXN];
int n,m;
int w[MAXN],v[MAXN];
typedef struct node{
int x,y;
}node;
node d[MAXN];
vector<int>vec[MAXN];
bool vis[MAXN],c[MAXN];
int st[MAXN],tot,cnt;
vector<int>circle[MAXN];
void tarjan(int x,int y){
cnt++;
dec(i,tot,1){
if(st[i]==y)break;
circle[cnt].pb(st[i]);
}
circle[cnt].pb(y);
}
void dfs(int x){
vis[x]=1;st[++tot]=x;c[x]=1;
for(int i=0;i<vec[x].size();i++){
int t=vec[x][i];
if(c[t])tarjan(x,t);
else if(!vis[t])dfs(t);
}
tot--;c[x]=0;
}
int find1(int x){
if(x==f[x])return x;
return f[x]=find1(f[x]);
}
int dp[MAXN][NM];
void _dfs(int x){
if(w[x]<=m)dp[x][w[x]]=v[x];
link(x){
_dfs(j->t);
for(int i=m;i>=w[x]+w[j->t];i--)for(int k=w[j->t];k<=i-w[x];k++)dp[x][i]=max(dp[x][i],dp[j->t][k]+dp[x][i-k]);
}
}
int ci[MAXN];
int main(){
n=read();m=read();
inc(i,1,n)f[i]=i;
inc(i,1,n)w[i]=read();
inc(i,1,n)v[i]=read();
int tot1=0;
inc(i,1,n){
int t=read();
if(t==0){continue;}
vec[t].pb(i);
++tot1;
d[tot1].x=t;d[tot1].y=i;
}
inc(i,1,n)if(!vis[i])dfs(i);
inc(i,1,cnt){
for(int j=1;j<circle[i].size();j++){
int t1=find1(circle[i][j]);int t2=find1(circle[i][j-1]);
if(t1==t2)continue;
f[t1]=t2;w[t2]+=w[t1];v[t2]+=v[t1];
}
}
inc(i,1,tot1){
int t1=find1(d[i].x);int t2=find1(d[i].y);
if(t1==t2)continue;
add(t1,t2);ci[t2]++;
}
inc(i,1,n){
int t1=find1(i);
if(t1==i&&!ci[i])add(0,i);
}
_dfs(0);
int ans=0;
inc(i,1,m)ans=max(ans,dp[0][i]);
printf("%d\n",ans);
}
2427: [HAOI2010]软件安装
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2519 Solved: 1090
[Submit][Status][Discuss]
Description
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Input
第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 )
Output
一个整数,代表最大价值。
Sample Input
3 10
5 5 6
2 3 4
0 1 1
5 5 6
2 3 4
0 1 1
Sample Output
5

浙公网安备 33010602011771号