HDU_5303 Delicious Apples(枚举+离散化)

题意:

圆形的道路长L,有N棵苹果树,每棵树上有Xi个苹果,现在拿着一个容量为K的篮子,问最少走多远距离能把所有苹果都拿回来。

思路:

看上去很简单,容易有思路,但是算法总会有问题,贪心不好做。最后还是参考了网上的解法...三种情况,左半边来回拿,右半边来回拿,转一圈拿。现在的问题就是转不转?转的话左右各拿几个?按照苹果树不好去计算,离散化每一个苹果,然后dp出单边的cost。之后枚举所有转圈的情况,得到最优解。

奉献几组样例给想要贪心的同学:

20 2 10
5 5
11 5
20
20 2 10
9 5
5 5
18
20 2 10
9 5
11 5
20
20 2 10
2 8
18 2
8
1000000000 1 1
500000000 100000
100000000000000

代码实现:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define LL long long
using namespace std;

const int MAX = 105500;

int T;
LL res;
int N,L,K;
int num[MAX];
LL dis1[MAX];
LL dis2[MAX];
int main(){
    scanf("%d",&T);
    while( T-- ){
        res = 0;
        scanf("%d%d%d",&L,&N,&K);
        int a,b;
        int cnt = 0;
        memset(dis1,0,sizeof(dis1));
        memset(dis2,0,sizeof(dis2));
        memset(num,0,sizeof(num));
        for( int i = 0; i < N; i++ ){
            scanf("%d%d",&a,&b);
            while( b-- ){
                num[cnt++] = a;
            }
        }

        vector<int> seq1, seq2;
        for( int i = 0; i < cnt; i++ ){
            if( num[i]*2 <= L ){
                seq1.push_back(num[i]);
            }
            else{
                seq2.push_back(L-num[i]);
            }
        }
        sort(seq1.begin(),seq1.end());
        sort(seq2.begin(),seq2.end());
        int len1 = seq1.size();
        int len2 = seq2.size();
        for( int i = 0; i < len1; i++ ){
            if( i+1 <= K ){
                dis1[i+1] = seq1[i];
            }
            else{
                dis1[i+1] = seq1[i]+dis1[i+1-K];
            }
        }
        for( int i = 0; i < len2; i++ ){
            if( i+1 <= K ){
                dis2[i+1] = seq2[i];
            }
            else{
                dis2[i+1] = seq2[i]+dis2[i+1-K];
            }
        }
        res = (dis1[len1]+dis2[len2])*2;
        for( int i = 0; i <= K; i++ ){
            int left = max(0, len1-i);
            int right = max(0, len2-K+i);
            res = min(res, 2*(dis1[left]+dis2[right])+L);
        }
        printf("%I64d\n",res);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值