• 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
    ",ans);
        }
    }
  • 相关阅读:
    修改Chrome设置伪装成手机M站
    使用Chrome浏览器自动将文件下载到指定路径
    操作HTML5存储对象
    在HTML5的画布元素上进行绘画操作
    测试HTML5语言实现的视频播放器
    封装操作表格的公用类
    测试过程中发生异常或断言失败时进行屏幕截图
    浏览器中新开标签页(Tab)
    高亮显示正在操作的页面元素
    精确比较页面截图图片
  • 原文地址:https://www.cnblogs.com/tun117/p/6001973.html
Copyright © 2020-2023  润新知