题意:一个环长度为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; }
时间: 2024-10-23 03:50:07