题目
题意: 你在一座古墓里盗墓,古墓在T分钟时就会倒塌,你就挂了。古墓有n个房间,每个房间都有一定价值的宝藏,n-1条边,每条边有花费的时间,形成一棵树。如果逃不出去就输出… 如果能逃出去,那么输出能获得的最大价值是多少?
思路: 先dfs算出1-n路径需要的时间tmp tmp<T就不能逃出古墓。
假如可以逃出古墓。那么把1-n的路径的边长设为0,然后问题就转化为K-(1-n路径花的时间)时间内1-任意点再回到1点 可得到的最大价值是多少。
仔细想想,这个模型的转化是正确的,很好。
poj3345的弱化版
#include<cstdio>
#include<iostream>
#include<cstring>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=500+5,INF=0x3f3f3f3f;
struct Edge{int to,nex,len;}edge[N<<1];int head[N],tot;
inline void add(int from,int to,int len){
edge[++tot]=(Edge){to,head[from],len},head[from]=tot;
edge[++tot]=(Edge){from,head[to],len},head[to]=tot;
}
int val[N],dp[N][N],n,K;
int dfs(int x,int fa){
if(x==n) return 0;
for(int i=head[x];i;i=edge[i].nex){
int y=edge[i].to,w=edge[i].len;
if(y==fa) continue;
int tmp=dfs(y,x);
if(tmp!=-1){
edge[i].len=0;//其实只edge[i].len=0 因为dfs dfs2的顺序是一样的
return tmp+w;
}
}
return -1;
}
void dfs2(int x,int fa){
for(int i=0;i<=K;++i) dp[x][i]=dp[x][i]=val[x];
for(int i=head[x];i;i=edge[i].nex){
int y=edge[i].to,w=edge[i].len;
if(y==fa) continue;
dfs2(y,x);
for(int j=K;j>=0;--j)
for(int k=0;k<=j;++k)//k要从0开始 因为w可以为0 2*w就可以为0
if(k>=2*w) dp[x][j]=max(dp[x][j],dp[y][k-2*w]+dp[x][j-k]);
}
}
int main(){
while(~scanf("%d%d",&n,&K)){
m(head,0),tot=1;
for(int i=1,x,y,w;i<n;++i) scanf("%d%d%d",&x,&y,&w),add(x,y,w);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
K-=dfs(1,1);
if(K<0) {puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!");continue;}
m(dp,0),dfs2(1,1);
printf("%d\n",dp[1][K]);
}
}