[BZOJ2427][HAOI2010]软件安装:Tarjan缩点+树形DP

本题智障题,就是只有智障才会写错的那种......

乍一看很像一道洛谷上很水的树形DP题“选课”。

But......

记得某NOI签到题中有这样一句话:

依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,…,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环)

本条件完全不适用于此题。

因为给出的依赖关系很可能出现环(这不柯学),所以在进行树形DP之前,要先用Tarjan把每个环缩点。之后我们就得到一个森林,再令n+1号结点为虚拟结点,为森林中每棵树的根结点共同的爸爸(好像有点奇怪,不管了)。

再进行树形DP即可。

注意数组的初始化。(不同的人写的初始化方式不同,当然,这个法则对智障也同样适用)

完了。

就这道题我数组处理的时候少写了个memset()后当场爆炸30分。(这30分咋来的我也不知道)

智障的代码,正因如此有99行:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 using namespace std;
 7 const int MAXN=205;//因为缩点所以要开2倍数组。 
 8 const int MAXM=505;
 9 int n,m,f[MAXN][MAXM],g[MAXM],w[MAXN],v[MAXN],d[MAXN],bel[MAXN],deg[MAXN],siz[MAXN];
10 int dfn[MAXN],low[MAXN],tot,stc[MAXN],top;
11 bool ins[MAXN],linked[MAXN][MAXN];
12 int head[MAXN],ecnt;
13 struct Edge{
14     int to,nxt;
15 }e[MAXN];
16 void add_edge(int bg,int ed){
17     ecnt++;
18     e[ecnt].nxt=head[bg];
19     e[ecnt].to=ed;
20     head[bg]=ecnt;
21 }
22 void tarjan(int x){
23     dfn[x]=low[x]=++tot;
24     stc[++top]=x;
25     ins[x]=1;
26     for(int i=head[x];i;i=e[i].nxt){
27         int ver=e[i].to;
28         if(!dfn[ver]){
29             tarjan(ver);
30             low[x]=min(low[x],low[ver]);
31         }
32         else if(ins[ver]){
33             low[x]=min(low[x],low[ver]);
34         }
35     }
36     if(low[x]==dfn[x]){
37         int temp=++n;
38         while(stc[top+1]!=x){
39             bel[stc[top]]=temp;
40             ins[stc[top]]=0;
41             top--;
42         }
43     }
44 }
45 void dfs(int x){
46     if(!head[x]){
47         siz[x]=w[x];
48         f[x][w[x]]=v[x];
49         f[x][0]=0;
50         return;
51     }
52     int tot=0;
53     f[x][0]=0;
54     for(int i=head[x];i;i=e[i].nxt){
55         int ver=e[i].to;
56         dfs(ver);
57         tot+=siz[ver];
58         for(int j=min(tot,m);j>=0;j--)
59             for(int k=0;k<=siz[ver];k++){
60                 if(k>j) break;
61                 f[x][j]=max(f[x][j],f[x][j-k]+f[ver][k]);
62             }
63     }
64     for(int i=0;i<=m;i++) g[i]=f[x][i];
65     memset(f[x],0xcf,sizeof f[x]);
66     for(int i=w[x];i<=m;i++) f[x][i]=g[i-w[x]]+v[x];
67     f[x][0]=0;
68     siz[x]=tot+w[x];
69 }
70 int main(){
71     scanf("%d%d",&n,&m);
72     int pren=n;
73     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
74     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
75     for(int i=1;i<=n;i++){
76         scanf("%d",&d[i]);
77         add_edge(d[i],i);
78     }
79     for(int i=1;i<=pren;i++)
80         if(!dfn[i]) tarjan(i);
81     for(int i=1;i<=pren;i++){
82         w[bel[i]]+=w[i];
83         v[bel[i]]+=v[i];
84         for(int j=head[i];j;j=e[j].nxt){
85             int ver=e[j].to;
86             if(bel[i]!=bel[ver]&&!linked[bel[i]][bel[ver]])
87                 add_edge(bel[i],bel[ver]),linked[bel[i]][bel[ver]]=1,deg[bel[ver]]++;
88         }
89     }
90     for(int i=pren+1;i<=n;i++)
91         if(!deg[i]) add_edge(n+1,i);
92     memset(f,0xcf,sizeof f);//只有智障才会使用的初始化方式。 
93     dfs(n+1);
94     int ans=0;
95     for(int i=0;i<=m;i++)
96         ans=max(ans,f[n+1][i]);
97     printf("%d\n",ans);
98     return 0;
99 }

erkokoko~

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9260251.html