cogs 444. [HAOI2010]软件安装
★★☆ 输入文件:
install.in输出文件:
install.out简单对比
时间限制:1 s 内存限制:128 MB
【问题描述】
现在我们的手头有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
题解:
根据依赖关系可以画出来一张图,有三种可能的情况:1.依赖关系构成一棵树 2.依赖关系构成一个环 3.依赖关系构成一个环下面吊着一棵树。因为有2,3这些情况,所以要先有tarjan预处理一下,缩环为点,重新建图。
对于建好的图,跑一边树形背包即可,思想类似于01背包,f[x][tot]表示以x为根,容量为tot的最大收益。把x的各个子树看成物品,再枚举每个子树所分给的容量,tot从大到小转移。
还有一点,f[x][tot]保证x要算进去,最后处理一下即可保证。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; const int maxn=200,maxm=600; int N,M,W[maxn],V[maxn],fa[maxn]; int val[maxn],cost[maxn],f[maxn][maxm]; vector<int> to[maxn],son[maxn]; int stac[maxn],top=0,dfn[maxn],low[maxn],inkin[maxn],tot,Index; bool instac[maxn]; vector<int> kin[maxn]; inline void tarjan(int x){ dfn[x]=low[x]=Index++; stac[++top]=x; instac[x]=true; for(int i=0;i<to[x].size();i++){ int y=to[x][i]; if(dfn[y]==-1){ tarjan(y); low[x]=min(low[x],low[y]); } else if(instac[y]!=0){ low[x]=min(low[x],dfn[y]); } } if(dfn[x]==low[x]){ tot++; int y; do{ y=stac[top--]; instac[y]=false; kin[tot].push_back(y); inkin[y]=tot; }while(y!=x); } } inline void calc(int x){ if(son[x].size()==0){ for(int i=cost[x];i<=M;i++) f[x][i]=val[x]; return ; } for(int i=0;i<son[x].size();i++) calc(son[x][i]); for(int i=0;i<son[x].size();i++){ int y=son[x][i]; for(int tot=M;tot>=0;tot--){ for(int j=0;j<=tot;j++){ f[x][tot]=max(f[x][tot],f[x][tot-j]+f[y][j]); } } } for(int i=M;i>=0;i--){ if(i>=cost[x]) f[x][i]=f[x][i-cost[x]]+val[x]; else f[x][i]=0; } } int main(){ scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) scanf("%d",&W[i]); for(int i=1;i<=N;i++) scanf("%d",&V[i]); for(int i=1;i<=N;i++){ scanf("%d",&fa[i]); to[fa[i]].push_back(i); } memset(dfn,-1,sizeof(dfn)); for(int i=1;i<=N;i++){ if(dfn[i]==-1) tarjan(i); } for(int i=1;i<=tot;i++){ int y=kin[i][0]; if(kin[i].size()>=2){//形成一个环 ,取其中任意一点,缩环为点 val[y]=V[y]; cost[y]=W[y]; son[0].push_back(y); for(int j=1;j<kin[i].size();j++){ val[y]+=V[kin[i][j]]; cost[y]+=W[kin[i][j]]; } } else{//是一棵树上的某一点,直接复制 if(fa[y]==0) son[0].push_back(y); else{ int xx=inkin[fa[y]]; int yy=kin[xx][0]; son[yy].push_back(y); } val[y]=V[y]; cost[y]=W[y]; } } val[0]=0; cost[0]=0; calc(0); printf("%d",f[0][M]); return 0; }
- USB OTG学习
- git操作过程
- 在进程间可公用的全局变量
- phyton3.5 django典型错误
- CMD 模块定义规范
- java.util 中的property
- 编译原理——实验 1.1用 FLEX自动构造词法分析程序
- 安装、设置与启动MySql绿色版的方法
- C# 自动运行代码 (创建windows 服务的形式 )
- Retrofit详解(一)(Retrofit创建过程)
- 基于CentOS的MySQL学习补充三--使用Shell批量创建数据库表
- Android复习之单例模式
- sqlite3的使用(iOS嵌入式关系数据库)
- 详解Linux2.6内核中基于platform机制的驱动模型
- 初始化job,并分析svn日志--initNEW1-UFT.bat
- UML类图实例
- Win7提示诊断策略服务未运行无法诊断检查网络解决方法
- netstat 命令详解
- 利用Python获取赶集网招聘信息前篇
- 线程池参数详解