码迷,mamicode.com
首页 > 其他好文 > 详细

uva 1407

时间:2015-05-28 00:32:25      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:

题意

   一棵n个节点的树,树的边有正整数权,表示两个节点之间的距离.你的任务是回答这样的询问:从跟节点出发,走不超过x单位的距离,
   最多能经过多少节点?同一个节点经过多次, 只能算一个.


思路

   这题同样是多天前看的, 在今天才想出解法的. 动态规划就是这么有意思 :)
   遍历n个节点, 有两种情况, 第一种是遍历完之后不回到出发点, 第二种是要回到出发点. 
   两种都可能会重复经过某些边, 但是显然还是第二种遍历的花费会更大
   在这一题中, 遍历之后不需要回到出发点.

   f(i, j, 0): 表示遍历子树i的j个节点,回到i点的最少花费
   f(i, j, 1): 表示遍历子树i的j个节点, 不回到i点的最少花费

 

莫名其妙的WA了。。。不过思路还是对的啊。。。

转移方程啊。。。。DP真是个神奇的东西啊。。。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<climits>
using namespace std;
vector<int> e[510],w[510];
int dp[510][510][2],n,q,siz[510];
void dfs(int u,int father)
{
    dp[u][1][1]=dp[u][1][0]=0;
    siz[u]=1;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        int val=w[u][i];
        if(v==father)
            continue;
        dfs(v,u);
        siz[u]+=siz[v];
        for(int j=siz[u];j>1;j--)
        {
            for(int k=1;k<=j&&k<=siz[v];k++)
            {
                dp[u][j][0]=min(dp[u][j][0],dp[u][j-k][0]+dp[v][k][0]+2*val);
                dp[u][j][1]=min(dp[u][j][1],dp[u][j-k][0]+dp[v][k][1]+val);
                dp[u][j][1]=min(dp[u][j][1],dp[u][j-k][1]+dp[v][k][0]+2*val);
            }
        }
    }
}
int main()
{
    int cas=1;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
            break;
        int x;
        for(int i=0;i<=n;i++)
            e[i].clear(),w[i].clear(),siz[i]=0;
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
                dp[i][j][0]=dp[i][j][1]=INT_MAX;
        }
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            e[x].push_back(y);
            e[y].push_back(x);
            w[x].push_back(z);
            w[y].push_back(z);
        }
        dfs(0,-1);
        scanf("%d",&q);
        printf("Case %d:\n",cas++);
        while(q--)
        {
            int ans=0;
            scanf("%d",&x);
            for(int i=1;i<=n;i++)
            {
                if(dp[0][i][1]<=x||dp[0][i][0]<=x)
                {
                    ans=i;
                }
                else
                    break;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

  

 

uva 1407

标签:

原文地址:http://www.cnblogs.com/water-full/p/4534758.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!