HDU 5303--Delicious Apples

http://acm.hdu.edu.cn/showproblem.php?pid=5303

题意:长度为L的圈上,有n棵苹果树,每次最多摘k个,求把所有苹果树上的苹果都摘回起点0上的最短距离。所有树上的苹果总和不超过1e5.

思路:有点贪心思想,苹果取回,要么取了原路返回,要么绕一圈再回去。但是可以发现,绕一圈的情况最多有一次,从中间平分,左后两边能满k运回去的,一定原路返回优于绕圈,因为有k个的约束,所以还要找到最小的左右原路返回的最小点,然后就可以分析,若存在绕圈的情况时的消耗,取走的一定是中间连续的k个。左右的分别就近原路返回。

感想:一开始也是贪心思想,但是做的方法逻辑性不够清晰,所以一直WA,今天就看了题解,感觉抓住所有苹果数不超过1e5这一点,将问题转化成对于每一个苹果考虑其走向,比较有意思

拓展:数据量不大时,可以考虑一下转换对象。具体题目还没想到~~

代码:

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
long long T,n,l,k,a,b;
long long ans,dpl[100005],dpr[100005],poit[100005],ant;
struct AA
{
    long long rt,num;
    bool operator<(const AA &aa)const
    {
        return rt<aa.rt;
    }
}pos[100050];
int main()
{
    scanf("%lld",&T);
    while(T--)
    {
        ant=0;
        ans=0;
        scanf("%lld%lld%lld",&l,&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&pos[i].rt,&pos[i].num);
        }
        sort(pos+1,pos+1+n);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=pos[i].num;j++)
            {
                poit[++ant]=pos[i].rt;
            }
        }
        int j;
        for(int i=1;i<=ant;i++)
        {
            j=max((long long)0,i-k);
            dpl[i]=dpl[j]+poit[i]*2;
        }
        dpl[ant+1]=dpr[ant+1]=0;
        for(int i=ant;i>=1;i--)
        {
            j=min(i+k,ant+1);
            dpr[i]=dpr[j]+(l-poit[i])*2;
        }
        ans=dpr[1];
        for(int i=1;i<=ant;i++)
        {
            ans=min(ans,dpl[i]+dpr[i+1]);
        }
        for(int i=0;i+k<=ant;i++)
        {
            ans=min(ans,dpl[i]+dpr[i+k+1]+l);
        }
        if(k>ant) ans=min(ans,l);
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37868325/article/details/81081780