思路
存图用时一个晚上,树形dp用时一个上午
首先我们这道题的存图可谓是读入紫题难度。。。看大佬们的存图好短为啥我的就这么长呢
这道题,我们假设走廊用时为边权。由于这是一棵树,我们走的时候是只能有唯一路径的,也就是你怎么进来的怎么出去,每条路一定要走两边,存图的时候便可以直接把路径长度开 2 2 2倍
找到有画的房间后,假设房间有 n n n幅画,因为搬一个走需要 5 s 5s 5s,这个可以转化成在这个房间面前有 n n n条走廊,每个长度为 5 5 5,连接到 n n n个点,每个点权值为1
紫题的存图就是这样,然后我们把边权视为时间,点权视为价值,跑一个树形dp分组背包就好了
设dp[u][j]表示以 u u u为根节点,用共计 j j j时间获得的最大价值,对于 u u u的每条出边 ( u , v ) (u,v) (u,v),有状态转移方程
d p [ u ] [ j ] = m a x ( d p [ u ] [ j ] , d p [ v ] [ k ] + d p [ u ] [ j − k − ( u , v ) ] ) dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k-(u,v)]) dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j−k−(u,v)])
其中
d p [ u ] [ 0 ] = 0 , e d g e [ i ] . d i s ≤ j ≤ s , 0 ≤ k ≤ j − ( u , v ) dp[u][0]=0,edge[i].dis\leq j\leq s,0\leq k\leq j-(u,v) dp[u][0]=0,edge[i].dis≤j≤s,0≤k≤j−(u,v)
d p dp dp精髓就式子和边界,我还有什么可讲的么 q w q qwq qwq
后面再来看这道题,感觉题解区有点不对劲,一个房间如果必定取完所有的画的话也能A了,然后又搞了一堆玄学的操作还是能A,于是我自己写了一个新题目,数据经过加强了qwq,题解见主页SOI文集的round0
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int orz=500100;
struct EDGE{
int ver,dis,nxt,pre,num;
}edge[orz];
int head[orz],n,m,cnt,size[orz],v=2;
int dis[orz],s,l,r,f[5001][1001],ans;
inline int read(){
int sym=0,res=0;char ch=0;
while (ch<'0'||ch>'9')sym|=(ch=='-'),ch=getchar();
while (ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return sym?-res:res;
}
void file(){
freopen("read.in","r",stdin);
freopen("write.out","w",stdout);
}
void add(int u,int v,int t){
edge[++cnt].ver=v;
edge[cnt].nxt=head[u];
edge[cnt].pre=u;
edge[cnt].dis=t;
head[u]=cnt;
}
void dfs(int u){//可怕的存图
int t=read()<<1,tmp=read();v++;add(u,v,t);
if (tmp){
for (int i=1;i<=tmp;i++){
add(v,v+i,5);dis[v+i]=1;
}v+=tmp;
}else{
dfs(v);
}
t=read()<<1;v++;tmp=read();add(u,v,t);
if (tmp){
for (int i=1;i<=tmp;i++){
add(v,v+i,5);dis[v+i]=1;
}v+=tmp;
}else{
dfs(v);
}
}
void dp(int u){
f[u][0]=dis[u];
for (int i=head[u];i;i=edge[i].nxt){
int v=edge[i].ver;dp(v);
for (int j=s;j>=edge[i].dis;j--){
for (int k=j-edge[i].dis;k>=0;k--){
f[u][j]=max(f[u][j],f[v][k]+f[u][j-k-edge[i].dis]);
}
}
}
}
int main(){file();
s=read()-1;
int t=read()<<1;dis[2]=read();add(1,2,t);
if (!dis[2])dfs(2);dp(1);
for (int i=1;i<=s;i++){
ans=max(ans,f[1][i]);
}
printf("%d",f[1][s]);
return 0;
}