修塔游戏题解

修塔游戏

http://www.nowcoder.com/questionTerminal/50f139741ff74f919bd4972f503631c2

思路,对高度为h的塔,都假定比它高和矮的塔向它靠拢,计算出最终达到共有k座高度为h的塔的最少操作次数,并最终计算所有高度的操作次数中的最小次数即为答案。
我使用map来保存每种高度的塔的数量。使用去重的vector保存排好序的塔。
同时使用四个vector保存计算所需要的变量。对于每一个高度的塔,算出左边都变为它的高度总共使用的操作次数,使用dp的方法累积计算,右边同理。其次还要计算每一个高度的塔左右两侧不同高度塔的数量。
最后只用一次遍历塔的数组,就能用这些状态算出每一种高度最少操作次数。
关键:每一种高度的塔的左侧操作次数是左侧都变为前一个高度的塔(towsLeftOp[i-1])再变为只比它高度少1的塔(+(tows[i]-tows[i-1]-1)*towsLeftNums[i-1])。右侧同理。
比较每一种高度的塔数量和它左右的塔数量,可以计算出最小需要发生变化的次数。

#include <algorithm>
#include <iostream>
#include <vector>
#include<map>
using namespace std;

int main()
{
    vector<int> tows;
    vector<int> towsLeftNums;
    vector<int> towsRightNums;
    vector<int> towsLeftOp;
    vector<int> towsRightOp;
    map<int,int>tmap;
    int n=0;int k=0;
    cin>>n>>k;
    for(int i=0;i<n;i++)
    {
        int t=0;cin>>t;
        tows.push_back(t);
        tmap[t]++;
    }
    sort(tows.begin(),tows.end());
    tows.erase(unique(tows.begin(), tows.end()), tows.end());
    for(int i=0;i<tows.size();i++)
    {
        if(i==0) 
            {
                towsLeftOp.push_back(0);
                towsLeftNums.push_back(tmap[tows[i]]);
            }
        else
        {
            towsLeftNums.push_back(towsLeftNums[i-1]+tmap[tows[i]]);
            int op=(tows[i]-tows[i-1])*towsLeftNums[i-1]+towsLeftOp[i-1];
            towsLeftOp.push_back(op);
        }    
    }
    for(int i=tows.size()-1;i>=0;i--)
    {
        if(i==tows.size()-1) 
        {
            towsRightOp.push_back(0);
            towsRightNums.push_back(tmap[tows[i]]);
        }

        else
        {
            towsRightNums.push_back(towsRightNums[tows.size()-i-2]+tmap[tows[i]]);
            int op=(tows[i+1]-tows[i])*towsRightNums[tows.size()-i-2]+towsRightOp[tows.size()-i-2];
            towsRightOp.push_back(op);
        }    
    }
    reverse(towsRightOp.begin(),towsRightOp.end());
    reverse(towsRightNums.begin(),towsRightNums.end());



    vector<int> ops;
    for(int i=0;i<tows.size();i++)
    {
        int leftOp=0;
        int rightOp=0;
        if(i>0)
        leftOp=towsLeftOp[i-1]+(tows[i]-tows[i-1]-1)*towsLeftNums[i-1];
        if(i<tows.size()-1)
        rightOp=towsRightOp[i+1]+(tows[i+1]-tows[i]-1)*towsRightNums[i+1];
        int leftTows=0;
        if(i>0)
        leftTows=towsLeftNums[i-1];
        int self=tmap[tows[i]];
        int rightTows=0;
        if(i<tows.size()-1)
        rightTows=towsRightNums[i+1];
        if(self>=k)
        {
            ops.push_back(0);
        }
        else
        {
            int times=0;
            if(self+leftTows<k&&self+rightTows<k)
            {
                times=leftOp+rightOp+k-self;
            }
            else if(self+leftTows>=k)
            {
                times=leftOp+k-self;
                if(self+rightTows>=k)
                {
                int times2=rightOp+k-self;
                if(times2<times)
                times=times2;
                }
            }
            else if(self+leftTows<k)
            {    
                times=rightOp+k-self;
            }
            ops.push_back(times);
        }

    }
    cout<<*min_element(ops.begin(),ops.end());
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
2024-12-18 15:35
程序员牛肉:完全是在胡写简历。 我很好奇你干嘛要在教育经历里面写你是软件二班的班长?你写它的目的是什么?我觉得真的就是很突兀。给我第一感觉就是:你真的是一个心智健全的成年人吗? 另外我也很好奇你是怎么做到参加了这么多所谓的计算机比赛,完事儿一个拿得出手的项目都没有。 自己的项目经历还是图书馆管理系统这种垃圾东西……我的的建议是你都不如大幅度删减一下自己的水奖项,看着真的给人一种又水又学傻了的感觉。 计算机不看奖项,看院校和个人能力。 计算机是强工科,你要投后端的你就应该明白,人家招你进去是指望你干活儿的。那你觉得你这份简历有展示出你的后端水平吗? 你动动你的脑子想一想,人家面试官要想通过你的简历看出你的项目开发能力,最重要的板块就是两个,第一个是你的实习,第二个是你的项目。你没有实习,是不是就应该在项目上好好琢磨琢磨? 你自己看看你项目写的什么描述,你作为一个要后端岗位的应届生,你对你自己项目的描述还仅仅停留在使用mySQL,使用JAVA,使用spring boot框架。给人一眼感觉就感觉完全就是你做的玩具。可能就是你哪一个学期做的课设。 对于应届生来讲,在项目板块要尽量突出自己的技术能力,因为谈业务你肯定也不懂。简单来讲,你的项目要清晰准确的表达:你用哪种技术解决了现有的哪种技术问题,带来了多少的效益提升? 所有关于项目的描述都围绕我说的这种表达方式去写。不要自己自嗨式的写一堆垃圾上去 你既没有实习项目,又没有一个比较好一点的项目,而且院校也比较差,所以找工作会异常的难找。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务