题目地址:http://exercise.acmcoder.com/online/online_judge_ques?ques_id=3358&konwledgeId=157
题目:
游戏漫长的前夕版本让无聊的小萌越发的无聊了……为了打发无聊的时间,有效的利用月卡优势,小萌打算开始练习烹饪技能。
现在小萌要做N个食物,第i个食物需要a[i]个单位的肉,现在小萌把肉买来了,是一整块的,他发现每次切肉都要消耗活力,
消耗值等于切的肉的大小:比如肉大小为21个单位,那么小萌切一次则消耗了21点活力。小萌的刀法非常好,
能准确的切分任何他想要的单位的肉,现在小萌想知道,要将这块肉分成他想要的N份,最少需要多少活力。
(买来的肉的大小等于N块肉之和)
提供一种超时但是正确的解法(60%通过,剩下的超时),希望如果有更好的方法请留言告诉我,超时坑爬不出来了/(ㄒoㄒ)/~~~
思路(分治):
一个序列0...n,将它分为0...cutIndex,cutIndex+1,...,n两部分,cutIndex选取可以使得两部分子序列和的差值最小的位置。每次将序列分为两部分,让两部分子序列和尽量相近,这样就分成了两个较小的子问题。result存储需要的活力值,如果切分前的序列长度大于2,需要切分,result增,如果切分前的序列长度等于1,退出递归。
#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;
int result = 0;
int findCut(vector<int>&vc,int startIndex,int endIndex)
{
int cutIndex = 0;
if(endIndex-startIndex<=1)//len <= 2
{
cutIndex = startIndex;
return cutIndex;
}
int sum = 0;
for(int i=startIndex;i<=endIndex;i++)
{
sum+=vc[i];
}
int halfSum = sum/2;
int sumTemp = 0,sumTemp2 = 0;
for(int i=startIndex;i<=endIndex;i++)
{
sumTemp+=vc[i];
sumTemp2 = sumTemp + vc[i+1];
if(sumTemp<=halfSum&&sumTemp2>halfSum) {
//cutIndex是0~cutIndex总和刚好小于或者刚刚大于halfSum的值,关键在于两边和差最小
if (abs((sum - sumTemp) - sumTemp) < abs((sum - sumTemp2) - sumTemp2)) {
cutIndex = i;
return cutIndex;
} else {
cutIndex = i + 1;
return cutIndex;
}
}
}
}
void countArray(vector<int>vc,int start,int end)
{
// cout<<"start:"<<start<<" "<<"end:"<<end<<endl;
int cutI = findCut(vc,start,end);
// cout<<"cutIndex:"<<cutI<<endl;
if(start == end)//len = 1
return;
for(int i=start;i<=end;i++) //len>=2
{
result+=vc[i];
}
countArray(vc,start,cutI);
countArray(vc,cutI+1,end);
}
int main()
{
int N;
cin>>N;
vector<int>vc;
for(int i=0;i<N;i++)
{
int inNum;
cin>>inNum;
vc.push_back(inNum);
}
sort(vc.begin(),vc.end());
countArray(vc,0,vc.size()-1);
cout<<result;
}