|BZOJ 2427|树形DP|强连通分量|[HAOI2010]软件安装

BZOJ传送门
根据题目可以构造一幅图,可以得知这个图是一些森林和环,我们对图缩点,建立虚结点,使所有没有入度的强连通分量连接虚结点,再进行树上背包即可。

#include  
#include  
#include  
#include
#include
#define ms(i,j) memset(i,j, sizeof i);
using namespace std;
const int MAXN = 100 + 5, MAXM = 500 + 5;
int n,m;
int wi[MAXN], vi[MAXN];
vector<int> G[MAXN];

int s_size = 0, s_no[MAXN], s_wi[MAXN], s_vi[MAXN], ino[MAXN];
vector<int> RG[MAXN];

stack<int> s;
int ex[MAXN], sz = 0, dn[MAXN], low[MAXN];
void tarjan(int u)
{
    dn[u] = low[u] = ++sz;
    ex[u] = -1;
    s.push(u);
    for (int i=0;iint v = G[u][i];
        if (!ex[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (ex[v]==-1)
        {
            low[u] = min(low[u], dn[v]);
        }
    }
    if (low[u]==dn[u])
    {
        s_size++;
        int e;
        do
        {
            e = s.top(); s.pop();
            s_no[e] = s_size;
            s_wi[s_size] += wi[e];
            s_vi[s_size] += vi[e];
            ex[e] = 1;
        } while(e!=u);
    }
}
void rebuild()
{
    ms(ino,0);
    for (int u=0;u<=n;u++)
    {
        for (int j=0;jint v = G[u][j];
            if (s_no[v]!=s_no[u])
            {
                RG[s_no[u]].push_back(s_no[v]);
                ino[s_no[v]]++;
            }
        }
    }
    for (int i=1;i<=s_size;i++)
    if (!ino[i]&&s_no[0]!=i) RG[s_no[0]].push_back(i);
}
int f[MAXN][MAXM];
void dp(int u)
{
    for (int i=0;iint v = RG[u][i];
        if (!ex[v])
        {
            ex[v] = true;
            dp(v);
            for (int j=m-s_wi[u];j>=0;j--)
            for (int k=0;k<=j;k++)
            f[u][j] = max(f[u][j], f[u][j-k]+f[v][k]);
        }
    }
    for (int j=m;j>=0;j--)
    {
        if (j>=s_wi[u]) f[u][j] = f[u][j-s_wi[u]] + s_vi[u];
        else f[u][j] = 0;
    }
}
int main()  
{  
    scanf("%d%d", &n,&m); wi[0] = vi[0] = 0;
    for (int i=1;i<=n;i++) scanf("%d", &wi[i]);
    for (int i=1;i<=n;i++) scanf("%d", &vi[i]);
    for (int i=1;i<=n;i++)
    {
        int di;
        scanf("%d", &di);
        G[di].push_back(i);
    }
    ms(ex,0); ms(s_wi,0); ms(s_vi,0);
    for (int i=0;i<=n;i++) if (!ex[i]) tarjan(i);
    rebuild();
    ms(ex,0); ms(f,0); dp(s_no[0]);
    printf("%d\n", f[s_no[0]][m]);
    return 0;  
}  

你可能感兴趣的:(BZOJ,动态规划,-,树形,图论,-,连通分量)