luogu P2515 [HAOI2010]软件安装

本文探讨了一种解决特定图论问题的方法,通过缩点将有传递关系且可能成环的图转换为树结构,然后运用树形动态规划求解整棵树在分W空间的收益,特别关注子树在不同空间分配下的收益关系。文章详细介绍了从图的预处理到最终求解的全过程,包括使用Tarjan算法进行缩点、调整边关系、以及树形DP的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
自定义HP背景好评!

analysis

有传递关系,还可能成环?缩点!
缩点后呢?显然是一棵树了

求整棵树分W空间的收益,和子树分Wi空间的收益好像有点关系

子问题相似,边界问题就是叶子结点
emm,树形DP吗?

试一下,好像可以诶!

于是就这样做:

  1. 缩点
  2. 树形DP

时间复杂度 O(n3)O(n^3)O(n3)

code

#include<bits/stdc++.h>
using namespace std;
#define loop(i,s,e) for(register int i=s;i<=e;++i)
#define anti_loop(i,s,e) for(register int i=s;i>=e;--i)
#define clean(a,n) memset(a,n,sizeof(a))
#define isdegit(a) ((a>='0'&&a<='9'))

template<typename T>void read(T &x){
	x=0;char r=getchar();T neg=1;
	while(!isdegit(r)){if(r=='-')neg=-1;r=getchar();}
	while(isdegit(r)){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
	x*=neg;
}

const int maxn=100+10;
const int maxm=500+10;
int n,m;
int W[maxn],V[maxn],D[maxn];

struct node{
    int e;
    int nxt;
}edge[maxn<<1];
int head[maxn];
int cnt=0;

inline void addl(int u,int v){
    edge[++cnt].e=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
}

int dfn[maxn];
int low[maxn];
int sta[maxn];
int bel[maxn];
int sumW[maxn];
int sumV[maxn];
int col=0;
int nfp=0;
int top=0;
void tarjan(int u){
    dfn[u]=low[u]=++nfp;
    sta[++top]=u;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(!bel[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]){
        bel[u]=++col;
        sumW[col]+=W[u];
        sumV[col]+=V[u];
        while(sta[top]!=u){
            bel[sta[top]]=col;
            sumW[col]+=W[sta[top]];
            sumV[col]+=V[sta[top]];
            --top;
        }
        --top;
    }
}

struct road{
    int xi;
    int yi;
}line[maxn];

inline bool cmp(road a,road b){
    return ((a.xi==b.xi)?a.yi<b.yi:a.xi<b.xi);
}

int in[maxn];
#define belonging(x) x=bel[x]
inline void reset(){
    loop(i,1,cnt){
        belonging(line[i].xi);
        belonging(line[i].yi);
    }
    int _m=cnt;
    sort(line+1,line+1+_m,cmp);
    clean(head,-1);
    cnt=0;
    loop(i,1,_m){
        if(line[i].xi!=line[i].yi&&(line[i].xi!=line[i-1].xi||line[i].yi!=line[i-1].yi)){
            addl(line[i].xi,line[i].yi);
            ++in[line[i].yi];
        }
    }
}

int f[maxn][maxm];
void dfs(int u){
    loop(i,sumW[u],m)
    	f[u][i]=sumV[u];
	for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].e;
        dfs(v);
		anti_loop(j,m-sumW[u],0){
        	loop(k,0,j){
        		f[u][j+sumW[u]]=max(f[u][j+sumW[u]],f[u][j+sumW[u]-k]+f[v][k]);
			}
		}
    }
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("datain.txt","r",stdin);
    #endif // ONLINE_JUDGE
    clean(head,-1);
    clean(dfn,0);
    clean(low,0);
    clean(bel,0);
    clean(in,0);

    read(n);
    read(m);
    loop(i,1,n)
        read(W[i]);
    loop(i,1,n)
        read(V[i]);
    loop(i,1,n){
        read(D[i]);
        if(D[i]){
            addl(D[i],i);
			line[cnt].yi=i;
        	line[cnt].xi=D[i];
        }
    }

    loop(i,1,n)
        if(!dfn[i])
            tarjan(i);
    reset();
    loop(i,1,col){
        if(!in[i]){
            addl(0,i);
        }
    }
    dfs(0);
    printf("%d\n",f[0][m]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值