【Luogu】P2515软件安装(树形DP)

  题目链接

  这么水的题我一遍没A,而且前两次提交都只有十分。气死我了。本来我的博客拒收水题来着。

  Tarjan缩点之后跑树形DP即可。

  

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define maxn 300
#define maxm 600
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int w[maxn];
int c[maxn];
int dfn[maxn],ID;
int low[maxn];
int stack[maxn],top;
int col[maxn],cnt;
int colw[maxn],colc[maxn];
bool vis[maxn];
int f[maxn][maxm];
int indl[maxn];
int n,m;

struct Pic{
    struct Edge{
        int next,to;
    }edge[maxn*2];
    int head[maxn],num;
    Pic(){num=0;memset(head,0,sizeof(head));    }
    inline void add(int from,int to){
        edge[++num]=(Edge){head[from],to};
        head[from]=num;
    }
    void tarjan(int x){
        vis[x]=1;stack[++top]=x;
        dfn[x]=low[x]=++ID;
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(!dfn[to]){
                tarjan(to);
                low[x]=min(low[x],low[to]);
            }
            else if(vis[to])    low[x]=min(low[x],dfn[to]);
        }
        if(dfn[x]==low[x]){
            col[x]=++cnt;
            vis[x]=0;    colw[cnt]=w[x];    colc[cnt]=c[x];
            while(stack[top]!=x){
                vis[stack[top]]=0;    col[stack[top]]=cnt;
                colw[cnt]+=w[stack[top]];    colc[cnt]+=c[stack[top]];
                top--;
            }
            top--;
        }
    }
    void dfs(int x){
        for(int i=m;i>=colw[x];--i)    f[x][i]=colc[x];
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            dfs(to);
            for(int j=m;j>=0;--j)
                for(int k=0;j-k>=colw[x];++k)    f[x][j]=max(f[x][j],f[x][j-k]+f[to][k]);
        }
        return;
    }
}Old,New;

int main(){
    n=read();m=read();
    for(int i=1;i<=n;++i)    w[i]=read();
    for(int i=1;i<=n;++i)    c[i]=read();
    for(int i=1;i<=n;++i){
        int x=read();
        if(x)    Old.add(x,i);
    }
    for(int i=1;i<=n;++i)
        if(!dfn[i])    Old.tarjan(i);
    for(int i=1;i<=n;++i)
        for(int j=Old.head[i];j;j=Old.edge[j].next){
            int to=Old.edge[j].to;
            if(col[i]==col[to])    continue;
            New.add(col[i],col[to]);
            indl[col[to]]++;
        }
    for(int i=1;i<=cnt;++i)
        if(!indl[i])    New.add(0,i);
    New.dfs(0);
    printf("%d",f[0][m]);
    return 0;
}

 

转载于:https://www.cnblogs.com/cellular-automaton/p/8243064.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值