HDU 4003 [树][贪心][背包]

/*
大连热身A题
不要低头,不要放弃,不要气馁,不要慌张
题意:
给一棵树,每条边上有权值。给一个起点,放置n个机器人,要求使得任意一个节点至少被一个机器人经过。
每个机器人经过某条边时的代价为这条边的权值。反复经过需要反复累积。
问最小的代价是什么。

思路:
1.转化为背包问题。考虑给某个子树i个机器人的最小代价,即有i个机器人跑到某棵子树不回来。其中0个代表给某子树一个机器人,该机器人
遍历完该子树所有节点以后又返回该节点的代价。然后相当于每棵子树有几个物品,至少从中选择一个。进行分组背包。
2.为什么以上转化是成立的,即是否有可能把某个机器人指派到某棵子树以后,该机器人又跑到其它子树,最后停留在其它子树,而能使得花
费的代价更优。事实是不可能的,因为如果该节点跑到子树的某个叶子节点又返回母亲节点,代价肯定比一开始就指派给该子树的机器人,让
它先走到那个节点所经过的叶子节点,再回到子树的根花费的代价要大。所以可以将这个问题转化为分组背包。

*/
#include<bits/stdc++.h>
#define N 10060
using namespace std;
long long dp[N][2][15];
int k;
int fa[N];
long long inf=0x3f3f3f3f3f3f3f3f;
struct edge{
    int id;
    long long w;
    edge *next;
};
int ednum;
edge *adj[N];
edge edges[N<<1];
inline void addedge(int a,int b,long long w){
    edge *tmp=&edges[ednum++];
    tmp->id=b;
    tmp->w=w;
    tmp->next=adj[a];
    adj[a]=tmp;
}
void dfs(int pos){
    bool ok=0;
    for(edge *it=adj[pos];it;it=it->next){
        if(!fa[it->id]){
            ok=1;
            fa[it->id]=pos;
            dfs(it->id);
            dp[pos][0][0]+=dp[it->id][0][0]+2*it->w;
        }
    }
    if(ok){
        for(int i=1;i<=k;i++)dp[pos][0][i]=inf;
        for(edge *it=adj[pos];it;it=it->next){
            memset(dp[pos][1],0x3f,sizeof(dp[pos][1]));
            if(fa[it->id]==pos){
                for(int i=1;i<=k;i++){
                    for(int j=i;j<=k;j++){
                        if(dp[pos][0][j-i]!=inf)
                            dp[pos][1][j]=min(dp[pos][0][j-i]-dp[it->id][0][0]+(i-2)*it->w+dp[it->id][0][i],dp[pos][1][j]);
                    }
                }
                for(int i=1;i<=k;i++)dp[pos][0][i]=min(dp[pos][0][i],dp[pos][1][i]);
            }
        }
    }
}
int main()
{
    int n,s;
    while(scanf("%d%d%d",&n,&s,&k)!=EOF){
        memset(adj,NULL,sizeof(adj));
        ednum=0;
        for(int i=1;i<n;i++){
            int a,b;
            long long w;
            scanf("%d%d%lld",&a,&b,&w);
            addedge(a,b,w);
            addedge(b,a,w);
        }
        memset(fa,0,sizeof(fa));
        fa[s]=s;
        memset(dp,0,sizeof(dp));
        dfs(s);
        long long ans=inf;
        for(int i=0;i<=k;i++)ans=min(ans,dp[s][0][i]);
        printf("%lld\n",ans);
    }
}
时间: 2024-12-18 21:37:00

HDU 4003 [树][贪心][背包]的相关文章

HDU 4003 (树形DP+背包)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4003 题目大意:有K个机器人,走完树上的全部路径,每条路径有个消费.对于一个点,机器人可以出去再回来,开销2倍.也可以不回来,一直停在某个点(如果你的机器人数量足够多的话).问最小开销. 解题思路: 其实这题只能说是类树形背包. 用dp[i][j]表示在i点,有j个不回来的机器人走过的最小开销. 比如dp[i][0]就表示,i点及其子点全部靠其它点的不回来的机器人探索.所以机器人是一来一回开销2倍

HDU 4003 Find Metal Minaral 树上瞎搞分组背包

对于分组背包,每组选且只选一件商品的写法只想出了二维数组的写法. dp[s][k] 表示 在前s类中选取价格为 k 的商品的最优解. dp[s][k] = max( dp[s-1][k-product[s][j].c] + product[s][j].w).dp[s][k]每次只会有dp[s-1]更新得到,保证了前s-1类商品的选取. 对于此题,可以把每棵子树的情况看成一类商品,递归求解. dp[s][k]表示在s子树上投入k个机器人时的最优解. 当k == 0时,表示在s点投入1个机器人,且此

hdu 4003 Find Metal Mineral 【树形dp,分组背包】

题目:hdu 4003 Find Metal Mineral 题意:火星上发现了一些n个矿厂,有 k 个机器人从 s 点出发采矿,给出路段间的花费cost,求最小的花费采所有的矿. 分类:树形dp + 分组背包 分析:结论1:假如我们从 i点出发k个机器人采完以 k 为根节点的所有矿又回到 i 点,那么花费为 i 为根节点的cost 的和 乘以 k. 对于每个节点,定义状态:dp[i][j] 用 j 个机器人去采以 i 为根节点的子树的所有矿石的最小花费 状态转移方程:dp[father][nu

HDU 4912 LCA+贪心

Paths on the tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 531    Accepted Submission(s): 182 Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. Th

hdu 4869 Task(贪心)

题目链接:hdu 4869 Task 题目大意:有n台机器,m个任务,每个机器和任务都有有xi和yi,要求机器的xi,yi均大于等于任务的xi和yi才能执行任务.每台机器一天只能执行一个任务.要求完成的任务数尽量多,并且说金额尽量大.完成每个任务的金额为xi?500+yi?2 解题思路:贪心,mach[i][j]表示等级为i,时间为j的机器数量,task[i][j]表示等级为i,时间为j的机器数量.每次优先减少i,因为对应等级减少100,对应的金额代价也不会减少超过500(即时间减少1). 每次

HDU 2955 Robberies --01背包变形

这题有些巧妙,看了别人的题解才知道做的. 因为按常规思路的话,背包容量为浮点数,,不好存储,且不能直接相加,所以换一种思路,将背包容量与价值互换,即令各银行总值为背包容量,逃跑概率(1-P)为价值,即转化为01背包问题. 此时dp[v]表示抢劫到v块钱成功逃跑的概率,概率相乘. 最后从大到小枚举v,找出概率大于逃跑概率的最大v值,即为最大抢劫的金额. 代码: #include <iostream> #include <cstdio> #include <cstring>

hdu 3333 树状数组+离线处理

http://acm.hdu.edu.cn/showproblem.php?pid=3333 不错的题,想了很久不知道怎么处理,而且答案没看懂,然后找个例子模拟下别人的代码马上懂了---以后看不懂的话就拿个例子模拟下别人的代码 举个例子:1 3 3 5 3 5 查询 a, 2 4 b, 2 5 最初是这么想的:对于a查询,倘若把第二个数第三个数变成1个3,那么到b查询,又出现了两个3,再做处理似乎还是O(n),而且如果先出现2,5查询,后出现2,4查询,那么还需要把删除的数补回来.....o(╯

Hdu 3887树状数组+模拟栈

题目链接 Counting Offspring Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1757    Accepted Submission(s): 582 Problem Description You are given a tree, it’s root is p, and the node is numbered fr

HDU 4864 Task(贪心)

HDU 4864 Task 题目链接 题意:有一些机器和一些任务,都有时间和等级,机器能做任务的条件为时间等级都大于等于任务,并且一个任务只能被一个机器做,现在求最大能完成任务,并且保证金钱尽量多 思路:贪心,对于每个任务,时间大的优先去匹配,时间相同的,等级大的优先去匹配,因为时间占得多,时间多1就多500,而等级最多才差200.然后匹配的时候,尽量使用等级小的去匹配,而时间只要大于它的都可以用,因为是按时间优先,所以如果该时间能匹配大的,其他肯定也能匹配,那么肯定优先匹配大的,所以只要在等级