UVA 1407 Caves(树形dp)

来源:互联网 发布:c语言编程之道 pdf 编辑:程序博客网 时间:2024/06/08 11:52

这题定义状态f[i][j][0]和f[i][j][1]。

f[i][j][0]表示遍历以i为根节点的子树的j个节点并且不回到节点i,那么状态方程为f[i][j][0]=min(f[i][j][0],min(f[i][j-k][1]+f[v][k][0]+w,f[i][j-k][0]+f[v][k][1]+2*w);

f[i][j][1]表示遍历以i为根节点的子树的j个节点并且回到节点i,那么状态方程为f[i][j][1]=min(f[i[j][1],f[i][j-k]+f[v][k]+2*w);

这样最后输入距离x,那么只要遍历f[0][i][0](i从n到1递减),如果最小距离小于等于x,那么最多就是能到i个节点,第三维为0的原因是不回到根节点能走到的点肯定比回到根节点走到的点多。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define rep(i,a,b) for(int i=(a);i<(b);i++)#define ret(i,a,b) for(int i=(a);i>=(b);i--)#define ss(x) scanf("%d",&x)const int maxn=500+5;int tot[maxn];int adj[maxn][maxn];int f[maxn][maxn][2];int vis[maxn];int n;int dfs(int u){    vis[u]=1;    tot[u]=1;    rep(i,0,n){        if(adj[u][i]==0) continue;        if(vis[i]) continue;        tot[u]+=dfs(i);        vis[i]=0;    }    f[u][1][0]=f[u][1][1]=0;    rep(i,0,n){        if(adj[u][i]==0) continue;        int v=i,w=adj[u][i];        if(vis[v]) continue;        ret(j,tot[u],1){            for(int k=1;k<=tot[v]&&k<j;k++){                f[u][j][0]=min(f[u][j][0],min(f[u][j-k][1]+f[v][k][0]+w,f[u][j-k][0]+f[v][k][1]+2*w));                f[u][j][1]=min(f[u][j][1],f[u][j-k][1]+f[v][k][1]+2*w);            }        }    }    return tot[u];}int main(){    int kase=0;    while(true)    {        ss(n);if(n==0) break;        int u,v,d;        memset(adj,0,sizeof(adj));        rep(i,0,n-1) {ss(u);ss(v);ss(d);adj[u][v]=adj[v][u]=d;}        memset(vis,0,sizeof(vis));        memset(f,0x7f,sizeof(f));        dfs(0);        int q,x;        ss(q);printf("Case %d:\n",++kase);        rep(i,0,q){            ss(x);            ret(j,n,0) {if(f[0][j][0]<=x) {printf("%d\n",j);break;}}        }    }    return 0;}

0 0
原创粉丝点击