题意:
圆形的道路长L,有N棵苹果树,每棵树上有Xi个苹果,现在拿着一个容量为K的篮子,问最少走多远距离能把所有苹果都拿回来。
思路:
看上去很简单,容易有思路,但是算法总会有问题,贪心不好做。最后还是参考了网上的解法...三种情况,左半边来回拿,右半边来回拿,转一圈拿。现在的问题就是转不转?转的话左右各拿几个?按照苹果树不好去计算,离散化每一个苹果,然后dp出单边的cost。之后枚举所有转圈的情况,得到最优解。
奉献几组样例给想要贪心的同学:
20 2 10
5 5
11 5
20
20 2 10
9 5
5 5
18
20 2 10
9 5
11 5
20
20 2 10
2 8
18 2
8
1000000000 1 1
500000000 100000
100000000000000
代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define LL long long
using namespace std;
const int MAX = 105500;
int T;
LL res;
int N,L,K;
int num[MAX];
LL dis1[MAX];
LL dis2[MAX];
int main(){
scanf("%d",&T);
while( T-- ){
res = 0;
scanf("%d%d%d",&L,&N,&K);
int a,b;
int cnt = 0;
memset(dis1,0,sizeof(dis1));
memset(dis2,0,sizeof(dis2));
memset(num,0,sizeof(num));
for( int i = 0; i < N; i++ ){
scanf("%d%d",&a,&b);
while( b-- ){
num[cnt++] = a;
}
}
vector<int> seq1, seq2;
for( int i = 0; i < cnt; i++ ){
if( num[i]*2 <= L ){
seq1.push_back(num[i]);
}
else{
seq2.push_back(L-num[i]);
}
}
sort(seq1.begin(),seq1.end());
sort(seq2.begin(),seq2.end());
int len1 = seq1.size();
int len2 = seq2.size();
for( int i = 0; i < len1; i++ ){
if( i+1 <= K ){
dis1[i+1] = seq1[i];
}
else{
dis1[i+1] = seq1[i]+dis1[i+1-K];
}
}
for( int i = 0; i < len2; i++ ){
if( i+1 <= K ){
dis2[i+1] = seq2[i];
}
else{
dis2[i+1] = seq2[i]+dis2[i+1-K];
}
}
res = (dis1[len1]+dis2[len2])*2;
for( int i = 0; i <= K; i++ ){
int left = max(0, len1-i);
int right = max(0, len2-K+i);
res = min(res, 2*(dis1[left]+dis2[right])+L);
}
printf("%I64d\n",res);
}
return 0;
}