• HDOJ 4276 The Ghost Blows Light(树形DP+背包)


    长春网赛倒数第2题

    题意:给一颗带权树,树的边权代表通过所需的费用,树中每个节点有一个value,代表财富值,从结点1出发,求在时间T内到达结点n最多能带走的财富。

    分析:从1到n有一条必经之路,对这条路上的结点用树形DP求泛型背包,然后对这些点进行分组背包。

    View Code
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    using namespace std;
    #define MAX(a,b) ((a)>(b)?(a):(b))
    #define N 101
    int n,T,e;
    int first[N],next[N<<1],v[N<<1],t[N<<1],val[N];
    int dp[N][5*N],ans[5*N];
    int d[N],p[N];
    bool vis[N];
    void init()
    {
        e=0;
        memset(first+1,-1,sizeof(first[0])*n);
    }
    void add(int a,int b,int c)
    {
        v[e]=b;
        t[e]=c;
        next[e]=first[a];
        first[a]=e++;
    }
    void read()
    {
        int a,b,c;
        init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        for(int i=1;i<=n;i++)   scanf("%d",&val[i]);
    }
    int spfa()
    {
        memset(d+1,0x3f,sizeof(d[0])*n);
        memset(vis+1,0,sizeof(vis[0])*n);
        d[1]=0;
        queue<int>q;
        int a,b;
        q.push(1);
        vis[1]=1;
        while(!q.empty())
        {
            a=q.front(),q.pop();
            if(a==n)    break;
            vis[a]=0;
            for(int i=first[a];~i;i=next[i])
            {
                b=v[i];
                if(d[b]>d[a]+t[i])
                {
                    d[b]=d[a]+t[i];
                    p[b]=a;
                    if(!vis[b]) vis[b]=1,q.push(b);
                }
            }
        }
        return d[n];
    }
    void dfs(int a,int fa)
    {
        dp[a][0]=val[a];
        for(int i=first[a];~i;i=next[i])
        {
            int b=v[i];
            if(b==fa || vis[b]) continue;
            dfs(b,a);
            for(int j=T;j>=0;j--)
            {
                for(int k=0;j-k-2*t[i]>=0;k++)
                {
                    dp[a][j]=MAX(dp[a][j],dp[a][j-k-2*t[i]]+dp[b][k]);
                }
            }
        }
    }
    void solve()
    {
        for(int i=1;i<=n;i++)   memset(dp[i],0xc3,sizeof(dp[0][0])*(T+1));
        memset(vis+1,0,sizeof(vis[0])*n);
        p[1]=0;
        for(int b=n;b;b=p[b])   vis[b]=1;
        for(int i=1;i<=n;i++)   if(vis[i])
        {
            dfs(i,0);
        }
    
        memset(ans,0xc3,sizeof(ans[0])*(T+1));
        ans[0]=0;
        for(int a=n;a;a=p[a])
        {
            for(int j=T;j>=0;j--)
            {
                for(int k=0;k<=j;k++)
                {
                    ans[j]=MAX(ans[j],ans[j-k]+dp[a][k]);
                }
            }
        }
        int max=0;
        for(int i=0;i<=T;i++)   max=MAX(max,ans[i]);
        printf("%d\n",max);
    }
    int main()
    {
        while(~scanf("%d%d",&n,&T))
        {
            read();
            T-=spfa();
            if(T<0)   puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!");
            else    solve();
        }
        return 0;
    }
  • 相关阅读:
    无法嵌入互操作类型“ADOX.CatalogClass”。请改用适用的接口。
    编码:隐匿在计算机软硬件背后的语言(3)--二进制加法器
    编码:隐匿在计算机软硬件背后的语言(2)--二进制
    C#中Mutex的用法
    C#中创建二维数组,使用[][]和[,]的区别
    git同时存在两个账号(在同一台电脑上)——三步完成(已修正)
    C++之标准库vector
    C++之标准库map
    sublime和vscode 格式化Json ——两步走
    二十八、linux下权限管理chmod
  • 原文地址:https://www.cnblogs.com/algorithms/p/2679067.html
Copyright © 2020-2023  润新知