hdu 5303 Delicious Apples(背包)

题意:一个环长度为L,上面有n棵树,篮子一次可装K个苹果;

        给出每棵树的位置和树上的苹果数,求将所有苹果运回原点的最少的总距离;

思路:将环分为两半考虑,且若有绕环一圈的情况也只能有一次;

        以单个苹果为对象进行处理;

       考虑不绕圈的情况:每个半圈优先取最远的苹果;sum[i]表示取第i个苹果是的花费(距离);

       考虑绕圈的情况:枚举两个半圈共剩下k个苹果的情况,最后绕一圈;

      不绕圈和绕圈中的最小值即为所求值;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,m,l,num1,num2,cnt;
long long left[500010],right[500010];
long long sum1[500010],sum2[500010];
long long apple[500010];
long long ans;
int main()
{
    int i,j,k,a,b;
    scanf("%d",&t);
    while(t--)
    {
        cnt=0;num1=num2=0;
        memset(apple,0,sizeof(apple));
        memset(sum1,0,sizeof(sum1));
        memset(sum2,0,sizeof(sum2));
        scanf("%d%d%d",&l,&n,&k);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            for(j=1;j<=b;j++){
                apple[++cnt]=a;  //每个苹果的位置
            }
        }
        k=min(k,cnt);
        for(i=1;i<=cnt;i++){
            if(apple[i]*2<=l){
               left[++num1]=apple[i]; //左半圈
            }
            else{
                right[++num2]=l-apple[i];//右半圈
            }
        }
        sort(left+1,left+num1+1);  //从小到大
        sort(right+1,right+num2+1);
        for(i=1;i<=num1;i++){
            if(i<=k) sum1[i]=left[i];   //少于k时,取最远花费
            else sum1[i]=sum1[i-k]+left[i]; //把最远的先取完,在考虑剩余的
        }
        for(i=1;i<=num2;i++){
            if(i<=k) sum2[i]=right[i];
            else sum2[i]=sum2[i-k]+right[i];
        }
        ans=(long long)(sum1[num1]+sum2[num2])*2; //不绕圈的花费
        for(i=0;i<=num1&&i<=k;i++){
            ans=min(ans,(long long)(l+2*sum1[num1-i]+2*sum2[num2-(k-i)])); //左右共剩下k个
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(apple)