完美世界2017秋招真题 【编程题】小萌的烹饪生涯(C++)

题目地址: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值