2018/7/17 hdu5303 训练日记二

Problem Description

There are  apple trees planted along a cyclic road, which is  metres long. Your storehouse is built at position  on that cyclic road.
The th tree is planted at position , clockwise from position . There are  delicious apple(s) on the th tree.
You only have a basket which can contain at most  apple(s). You are to start from your storehouse, pick all the apples and carry them back to your storehouse using your basket. What is your minimum distance travelled?
There are less than 20 huge testcases, and less than 500 small testcases.

Input

First line: , the number of testcases.
Then  testcases follow. In each testcase:
First line contains three integers, .
Next  lines, each line contains .

Output

Output total distance in a line for each testcase.

Sample Input

2 10 3 2 2 2 8 2 5 1 10 4 1 2 2 8 2 5 1 0 10000

Sample Output

18 26

题意:

有一个圈,圈的长度是l,在正上方是0点,在圈上有n棵苹果树,给出每棵苹果树的位置和苹果的数量,现在一个人在0点的农场里,有一个小篮子,一次可以装k个苹果,问最少走多少距离可以把所有的苹果收回农场。

思路:

看了之后就觉得是贪心,怎么贪呢

对于摘苹果有几种情况:

1、正向去摘,然后按原路返回

2、反向去摘,然后按原路返回

3、走一圈

如果在圈上只剩下了k个苹果,可以一次摘走,如果这k个在一侧,或者在接近0点的两侧,那么走半圆是优的;

如果在两侧并且比较靠下方,那么直接走一圈就是优的。而且走一圈只可能出现一次,否则就可以用半圈来代替了。

题目中给出了所有的苹果不会超过10^5个,

让a[i]表示第i个苹果的位置,disr[i]表示正向摘完第i个需要的距离,disl[i]表示反向摘完第i个需要的距离,

然后通过它们找出如果没走过整圈需要的最小值,和走一个整圈需要的最小值,其中小的那个是结果。

如果k大于所有的苹果数,那么len的距离一定可以摘完,要特判一下最小值!!!

扩展:枚举+贪心

有n个点,用相同的线段去覆盖,当点在线段的端点才行,还有线段之间不相交

还有poj 1042 Gone Fishing类似

 

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL __int64
struct node{
    int x,a;
}p[100010];
int a[100010],cnt;
LL disl[100010],disr[100010];
int cmp(node t1,node t2){
    return t1.x<t2.x ;
}
int main(){
    int t,n,k;
    int i,j;
    LL len,ans;
    scanf("%d",&t) ;
    while( t-- ){
        scanf("%d %d %d", &len, &n, &k) ;
        for(i = 0 ; i < n ; i++) {
            scanf("%d %d", &p[i].x, &p[i].a) ;
        }
        sort(p,p+n,cmp) ;
        cnt = 1 ;
        for(i = 0 ; i < n ; i++) {
            for(j = 0 ; j < p[i].a ; j++)
                a[cnt++] = p[i].x ;
        }
        memset(disl,0,sizeof(disl)) ;
        memset(disr,0,sizeof(disr)) ;
        for(i = 1 ; i < cnt ; i++) {
            j = max(i-k,0) ;
            disr[i] = disr[j] + 2*a[i] ;
        }
        for(i = cnt-1 ; i > 0 ; i--) {
            j = min(i+k,cnt) ;
            disl[i] = disl[j] + 2*(len-a[i]) ;
        }
        ans = 0 ;
        for(i = 0 ; i < cnt ; i++) {
            if( ans == 0 ) ans = disr[i] + disl[i+1] ;
            else ans = min(ans,disr[i]+disl[i+1]) ;
        }
        for(i = 0 ; i+k+1 <= cnt ; i++)
            ans = min(ans,disr[i]+disl[i+k+1]+len) ;
        if( k >= cnt ) ans = min(ans,len) ;
        printf("%I64d\n", ans) ;
    }
    return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值