[HAOI2010]软件安装

题目描述

现在我们的手头有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 )

 

输出格式:

 

一个整数,代表最大价值

 

输入输出样例

输入样例#1:
3 10
5 5 6
2 3 4
0 1 1
输出样例#1:
5

首先对于每个i,从iDi建一条有向边。

在这里我们发现,依赖关系可以形成环。对于一个环,里面的节点要么都选,要么都不选。

所以,这里先Tarjan强连通分量缩点,构成一个新图,这样新图里的每个节点可以看成一个整体考虑

然后就变成裸的树形dp

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 struct Messi
  7 {
  8     int next,to;
  9 }edge[10001],edge2[10001];
 10 int head[10001],num,low[10001],dfn[10001],dfscnt,stack[10001],inStack[10001];
 11 int n,m,scnt,top,sccno[10001];
 12 int ans,num2,head2[10001],w[10001];
 13 int v[10001],V[10001],W[10001],f[501][1001];
 14 bool b[1001];
 15 void add(int u,int v)
 16 {
 17     num++;
 18     edge[num].next=head[u];
 19      edge[num].to=v;
 20      head[u]=num;
 21 }
 22 void add2(int u,int v)
 23 {
 24     num2++;
 25     edge2[num2].next=head2[u];
 26      edge2[num2].to=v;
 27      head2[u]=num2;
 28 }
 29 void dfs(int u)
 30 {int i,j;
 31     low[u]=dfn[u]=++dfscnt;
 32     stack[++top]=u;
 33      inStack[u]=1;
 34      for (i=head[u];i;i=edge[i].next)
 35      {
 36         int v=edge[i].to;
 37          if (dfn[v]==0)
 38          {
 39             dfs(v);
 40             low[u]=min(low[u],low[v]);
 41          }else if (inStack[v]) low[u]=min(low[u],dfn[v]);
 42      }
 43      if (dfn[u]==low[u])
 44      {
 45         ++scnt;
 46         while (top&&stack[top+1]!=u)
 47         {
 48             sccno[stack[top]]=scnt;
 49             inStack[stack[top--]]=0;
 50         }
 51      }
 52 }
 53 void dp(int x)
 54 {int i,j,k;
 55     for (i=head2[x];i;i=edge2[i].next)
 56     {
 57       int v=edge2[i].to;
 58         dp(v);
 59         for (j=m-V[x];j>=0;j--)
 60         {
 61             for (k=0;k<=j;k++)
 62             f[x][j]=max(f[x][j],f[x][k]+f[v][j-k]);
 63         }
 64     }
 65     for (j=m;j>=0;j--)
 66     if (j-V[x]>=0)
 67      f[x][j]=f[x][j-V[x]]+W[x];
 68      else f[x][j]=0;
 69 }
 70 int main()
 71 {int i,x,j;
 72   cin>>n>>m;
 73   for (i=1;i<=n;i++)
 74   scanf("%d",&v[i]);
 75   for (i=1;i<=n;i++)
 76   scanf("%d",&w[i]);
 77   for (i=1;i<=n;i++)
 78   {
 79     scanf("%d",&x);
 80     if (x) add(x,i);
 81   }    
 82   for (i=1;i<=n;i++)
 83        if (dfn[i]==0) dfs(i);
 84        for (i=1;i<=n;i++)
 85        {
 86          int u=sccno[i];
 87             W[u]+=w[i];
 88             V[u]+=v[i];
 89           for (j=head[i];j;j=edge[j].next)
 90            {
 91             int v=sccno[edge[j].to];
 92             if (u!=v) b[v]=1,add2(u,v);
 93            }
 94        }
 95    for (i=1;i<=scnt;i++)
 96    {
 97       if (b[i]==0)
 98       add2(scnt+1,i);
 99    }
100    dp(scnt+1); 
101    cout<<f[scnt+1][m];
102 }

 

posted @ 2017-09-23 15:30  Z-Y-Y-S  阅读(236)  评论(0编辑  收藏  举报