HDU - 5303(贪心)

这个题目的意思: 在一个长度为L的环上,0和L位置重叠,在0 - L的某些位置有n个点,每个点有一些苹果数目。现在一个人在0处,有个大小为K的篮子,要求用最小距离把所有苹果全运回0处。

分析:

对于直线上的一些点处,有某些苹果,直接从出发点出发,遇到苹果就装到篮子,装满就回,这样是最优的。(很好证明)

这个题目的特殊之处在于可以绕一圈装K个苹果回到0点

假设左右苹果总数目都大于K , 若进行绕圈,那么只会绕圈一次且个数为K。若多于2K必有一边超过K,那么可以让这K个从一边走,更优,若K<X<2K,那么可以让剩下的X-K从一边走更优。

所以当两边都大于K个时候,那么最多绕圈一次拿K个苹果,且是从中间到两边一段相邻的苹果,这样,直接暴力一下,即可。

其余情况下,就是在考虑绕圈时,要尽可能多的拿,就行了。

#include <set>
#include <cstdio>
#include <vector>
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <string>
#include<iomanip>
#include <algorithm>
using namespace std;
#define pii(x,y) make_pair(x,y)
#define clr(a, x) memset(a, x, sizeof a)
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define rep1(i,x,y) for(int i=x;i<=(int)y;i++)
typedef pair<int,int> pii;
typedef long long LL;
const int N = 101010;
const int inf = 0x3f3f3f3f;

struct node{
    int x,p;
    bool operator<(const node& rhs)const{
      return p<rhs.p;
    }
}a[N];
int bel[N];
int L,n,K,sum;
LL suml(int c){
    LL res=0;
    while(c>=K){
         res+=a[bel[c]].p*2;
         c-=K;
    }
    if(c) res+=a[bel[c]].p*2;
    return res;
}
LL sumr(int c){
    LL res=0;
    while(sum-c>=K){
         res+=(L-a[bel[c+1]].p)*2;
         c+=K;
    }
    if(sum-c>0) res+=(L-a[bel[c+1]].p)*2;
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
      scanf("%d %d %d",&L,&n,&K);
      sum = 0; int  l = 0,r = 0;
      rep1(i,1,n)
         scanf("%d %d",&a[i].p,&a[i].x);
      sort(a+1,a+1+n);
      rep1(i,1,n){
         rep1(j,sum+1,sum+a[i].x)
             bel[j]=i;
         sum+=a[i].x;
         if(a[i].p<=L/2){
              l = sum; r=sum;
         }
      }
      LL res = suml(l) + sumr(l);
      for(int i=1;i<K&&i<=l;i++){
          res = min(res,suml(l-i)+sumr(min((l-i+K),sum))+L);
      }
      cout<<res<<endl;
    }
    return 0;
}



你可能感兴趣的:(HDU - 5303(贪心))