大连网络赛 即 hdu 4003 Find Metal Mineral

20 篇文章 0 订阅

 大连网络赛 即 hdu 4003 Find Metal Mineral

这个题目我觉得应该可以做的,但是由于当时没看这个题,结果没做,现在看看,如果有时间,而且自己的状态非常好的话,也许是可以做出来的,

 

下面的代码是从网上掏的,自己最近没状态,懒得敲,先放在这儿供大家参考,

/*
题意:一棵有权树,从根结点中放入K个机器人,求用这K个机器人遍历所有的结点最少的权值和
分析:dp[i][j]表示对于以i结点为根结点的子树,放j个机器人所需要的权值和。
      当j=0时表示放了一个机器人下去,遍历完结点后又回到i结点了。状态转移方程类似背包
*/
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

const __int64 maxn=11000;
const __int64 maxm=21000;
struct edge
{
    __int64 u,v,w,next;
}e[maxm];
__int64 edgeNum,first[maxn],dp[maxn][15];

void Addedge(__int64 u,__int64 v,__int64 w)
{
    e[edgeNum].u=u,e[edgeNum].v=v,e[edgeNum].w=w,e[edgeNum].next=first[u],first[u]=edgeNum++;
    e[edgeNum].u=v,e[edgeNum].v=u,e[edgeNum].w=w,e[edgeNum].next=first[v],first[v]=edgeNum++;
}

void DFS(__int64 t,__int64 p)
{
    __int64 ii,i,j,k;
    for(k=first[t];k!=-1;k=e[k].next)
    {
        i=e[k].v;
        if(i==p) continue;
        DFS(i,t);
    }
    //first[t]=-1时说明树中只有一个结点
    if(first[t]==-1||(e[first[t]].next==-1&&p!=-1))//叶子结点,注意一定要把根结点排除。
    {
        for(i=0;i<=10;i++)
            dp[t][i]=0;
        return;
    }
    for(k=first[t];k!=-1;k=e[k].next)
    {
        i=e[k].v;
        if(i==p) continue;
        for(j=10;j>=0;j--)//跟01背包类似,方向不能换
        {    
            if(dp[t][j]==-1)//第一棵子树
            {
                if(j) 
                {//最多放j个在该子树中,不一定要全部到该子树中(有一些机器人就停在这个结点上)。当然一个不放肯定不是最好的
                    for(ii=1;ii<=j;ii++)
                        if(dp[t][j]==-1||dp[t][j]>dp[i][ii]+ii*e[k].w)
                            dp[t][j]=dp[i][ii]+ii*e[k].w;
                }
                else dp[t][0]=dp[i][0]+2*e[k].w;
                continue;
            }
            else//否则,若该子树放0个机器人
                dp[t][j]+=dp[i][0]+2*e[k].w;
            for(ii=1;ii<=j;ii++)
            {
                if(dp[t][j]>dp[t][j-ii]+dp[i][ii]+ii*e[k].w)
                    dp[t][j]=dp[t][j-ii]+dp[i][ii]+ii*e[k].w;
            }
        }
    }
}
int main()
{
    __int64 n,s,k,i,u,v,w;
    while(scanf("%I64d%I64d%I64d",&n,&s,&k)!=EOF)
    {
        memset(first,-1,sizeof(first));
        for(edgeNum=0,i=1;i<n;i++)
        {
            scanf("%I64d%I64d%I64d",&u,&v,&w);
            Addedge(u,v,w);
        }
        memset(dp,-1,sizeof(dp));
        DFS(s,-1);
        printf("%I64d\n",dp[s][k]);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值