寒假集训02 J hdu 5303 DP+枚举

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5303

题意:

在一圈长为l的圆圈周围种了n棵苹果树

有一个容积为k的篮子

圆圈的原点是0,顺时针方向记录了苹果树的位置以及苹果的数量

将苹果全部摘完,最少需要走多少路

篮子装满就必须走回原点



题目分析:

对这个环,有3种操作:

1.顺时针过去取

2.逆时针过去取

3.绕这个环一圈取

1和2如果走过了环的一半,就变成了3,所以1和2是不能走过环的一半的。

而对于1和2,每次取的k个苹果,其花费的距离必然为max(xi)*2|i=1,2...k,所以拿的这k个苹果的距离一定是当前这半环中的最大的k个,因为既然花费距离已定,那不如将这次操作的优化价值提升到最大,也就是每次都尽量消去距离最远的苹果。

对于3,同样,花费一定是L,每次也同样要消去距离最远的苹果。但是,可以发现,如果操作中出现了2次操作3,那么这个操作一定不是最优的,因为可以通过1和2两次操作取得两次操作3获得的苹果,且花费更低。所以操作中只可能出现一次操作3且这次操作3若要发生,一定发生在操作刚开始,因为此时进行操作3的优化价值是最大的。

综上得到以下解法:

1、先分左边和右边分别进行DP,求出最少距离。设dpl[i],dpr[i]分别表示采摘左边、右边的第i个苹果时的最少距离总和。

2、枚举走一圈情况下的左边和右边的苹果数量,得到距离和上面比较,取最小值。


注意点:

取值范围取long long, 输入最好用scanf()



#include <iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
#define N 100005
#define ll long long

int l[N], r[N];
ll dpl[N], dpr[N];
int main()
{
 //freopen("E:\input.txt", "r", stdin);
    int t;
    int L, n, k;
    int i;
    int n1, n2;
    ll sum;
    cin >> t;
    while (t--)
    {
        memset(l, 0, sizeof(l));
        memset(r, 0, sizeof(r));
        memset(dpl, 0, sizeof(dpl));
        memset(dpr, 0, sizeof(dpr));
        n1 = 0;
        n2 = 0;
        sum = 0;
        int x, a;
        cin >> L >> n >> k;
        //scanf("%d%d%d", &L, &n, &k);

        for (i = 0; i < n; i++)
        {
            //cin >> x >> a;
            scanf("%d%d", &x, &a);
            while (a--)
            {
                if (2 * x > L)
                {
                    l[++n1] = L - x;
                }
                else
                {
                    r[++n2] = x;
                }
            }
        }
        sort(l + 1, l + n1 + 1);
        sort(r + 1, r + n2 + 1);
        //sort(x, x + n);
        dpl[0] = 0;
        dpr[0] = 0;
        for (i = 1; i <= n1; i++)
        {
            if (i <= k)
            {
                dpl[i] = l[i];
            }
            else
            {
                dpl[i] = dpl[i - k] + l[i];
            }
        }
        for (i = 1; i <= n2; i++)
        {
            if (i <= k)
            {
                dpr[i] = r[i];
            }
            else
            {
                dpr[i] = dpr[i - k] + r[i];
            }
        }
        sum = 2 * (dpl[n1] + dpr[n2]);

        for (i = 0; i <= min(n1, k); i++) //枚举走一圈时左边苹果的数量
        {
            //k-i为走一圈时右边苹果的数量,n2-(k-i)就是右边原路返回采摘的苹果数量
            int j = max(n2 - (k - i), 0);
            最后的结果就是左边原路返回方案的花费加上右边原路返回的花费,再加上圈长
            sum = min(sum, 2 * (dpl[n1 - i] + dpr[j]) + L);
        }
   // cout << sum << endl;
      printf("%I64d\n", sum);

    }
    return 0;
}
 

hdu 5303  相关1

HDU 5303 相关2



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值