题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5303
题意:
在一圈长为l的圆圈周围种了n棵苹果树
有一个容积为k的篮子
圆圈的原点是0,顺时针方向记录了苹果树的位置以及苹果的数量
将苹果全部摘完,最少需要走多少路
篮子装满就必须走回原点
解题思路:
算出总的苹果数量
dp[ i ][ j ]表示的是摘了j个苹果时所走的最小路程
正着走一圈,逆着走一圈求出最小值
所以i的值只有两个 0或1
0表示正着走,1表示逆着走
转移方程式:dp[ i ][ sum ] = dp[ i ][ tmp ]+dis
sum是到目前为止的苹果数量,tmp=sum-k
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
#define inf 100005
#define ll __int64
struct node
{
ll x,a;
}p[inf];
ll dp[5][inf];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int t;
scanf("%d",&t);
ll maxn=1;
for(int i=0;i<18;i++) maxn*=10;
while(t--)
{
ll l;
ll n,k;
memset(dp,0,sizeof(dp));
scanf("%I64d%I64d%I64d",&l,&n,&k);
int ans=0;
for(int i=1;i<=n;i++)
{
scanf("%I64d%I64d",&p[i].x,&p[i].a);
ans+=p[i].a;
}
sort(p+1,p+1+n,cmp);
ll sum=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<p[i].a;j++)
{
ll tmp=0,dis=l;
if(sum-k>0) tmp = sum-k;
if(2*p[i].x<l) dis=2*p[i].x;
dp[0][sum] = dp[0][tmp]+dis;
sum++;
}
}
sum=1;
for(int i=n;i>=1;i--)
{
for(int j=0;j<p[i].a;j++)
{
ll tmp=0,dis=l;
if(sum-k>0) tmp = sum-k;
if(2*(l-p[i].x)<l) dis = 2*(l-p[i].x);
dp[1][sum] = dp[1][tmp]+dis;
sum++;
}
}
ll dis=maxn;
for(int i=0;i<=ans;i++)
{
dis = min(dis,dp[0][i]+dp[1][ans-i]);
}
printf("%I64d\n",dis);
}
return 0;
}