P1270 “访问”美术馆
2019-09-21
我肝了好久……
题目描述
经过数月的精心准备,Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动。艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室。Peer知道每个展室里藏画的数量,并且他精确测量了通过每条走廊的时间。由于经验老到,他拿下一幅画需要5秒的时间。你的任务是编一个程序,计算在警察赶来之前,他最多能偷到多少幅画。
样例的图……
Slove
树形DP-树形背包
mon[i]到节点i的用时
十年DP推方程
- 设计状态:d[i][j],以i为根节点,取画j副时的最少用时。
- 边界:d[i][j]=j*5,(i为展室,0<=j<=该展室画数)
- 转移方程:d[u][j]=min(d[u][j],d[u][j-k]+d[v][k]+mon[v]).(u到v有边;j为u的最大画数)
- 按照最大画幅,倒序枚举,用时低于S的就是答案。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1010
using namespace std;
int s;
int tree[N*10];
int mon[N],vl[N],cnt;
int d[N][N];
int sz[N],sum;
int first[N],nxt[N],to[N],len;
void add(int u,int v){
to[++len]=v;
nxt[len]=first[u];
first[u]=len;
}
void infs(int u){
mon[u]=mon[u]*2;
if(vl[u]){
sum+=vl[u];
for(int i=0;i<=vl[u];i++) d[u][i]=i*5;
return ;
}
scanf("%d%d",&mon[u*2],&vl[u*2]);
add(u,u*2);infs(u*2);
scanf("%d%d",&mon[u*2+1],&vl[u*2+1]);
add(u,u*2+1),infs(u*2+1);
}
void dfs(int u){
if(vl[u]){
sz[u]=vl[u];
return ;
}
for(int i=first[u];i!=-1;i=nxt[i]){
dfs(to[i]);
sz[u]+=sz[to[i]];
for(int j=sz[u];j>=0;j--){
for(int k=min(j,sz[to[i]]);k>=0;k--) d[u][j]=min(d[u][j],d[u][j-k]+d[to[i]][k]+mon[to[i]]);
}
}
}
int main()
{
memset(first,-1,sizeof(first));
for(int i=0;i<=1001;i++) for(int j=1;j<=1001;j++) d[i][j]=30000;
scanf("%d",&s);
s--;
add(0,1);
scanf("%d%d",&mon[1],&vl[1]);
infs(1);
dfs(0);
for(int i=sum;i>=0;i--){
if(d[0][i]<s){
printf("%d",i);
return 0;
}
}
return 0;
}