P2392 kkksc03考前临时抱佛脚

在这里插入图片描述
在这里插入图片描述

这道题咋一看上去就是贪心,用优先队列,每次弹出第一大第二大的元素,然后加上较小的那一个,将两者之差压入优先队列,一直循环到优先队列只有一个元素,加上剩下的那个元素即可。

#include <iostream>
#include <queue>
#define Max 666
using namespace std;
    int main()
    {
        int s[5];
        int a[Max];
        int sum=0;
        priority_queue<int, vector<int> ,less<int> > priorityQueue;
        for(int i=1;i<=4;i++)
        {
            cin>>s[i];
        }
        for(int i=1;i<=4;i++)
        {
            for(int j=1;j<=s[i];j++)
            {
                cin>>a[j];
                priorityQueue.push(a[j]);
            }
            while(!priorityQueue.empty())
            {
                if(priorityQueue.size()>=2)
                {
                    int x1=priorityQueue.top();
                    priorityQueue.pop();
                    int x2=priorityQueue.top();
                    priorityQueue.pop();
                    sum+=x2;
                    priorityQueue.push(x1-x2);
                }
                else
                {
                    sum+=priorityQueue.top();
                    priorityQueue.pop();
                }
            }
        }
        cout<<sum<<endl;
        return 0;
    }

自信满满的提交上去,竟然只有60分。。。。说实话,我只看得出来是贪心,题目这样例也能达到我自己认为的贪心策略的解,但机智如我,很快发现就是一道DP题,反正贪心我贪不来,可能可以贪心,是我太弱?

dp思路:如果一门功课的总时间为T,那么最好的情况就是T/2的时间学完这门功课,左右脑齐开动。但是也可能达不到T/2,所以我们选择几门功课尽可能到达T/2,此时就抓换为,T/2的背包,最多可以容纳多少价值的物品,此时的物品的重量和价值相当,也就是说学习时长等于物品的重量也等于物品的价值,如果选完后物品总价值为X(这门功课一部分的学习时长),则另一部分学习时长为T-X,此时判断哪一个更大即可。加上大的那个,即这门功课所花费的最少时间。

你也可以自己想办法,使得一部分的学习时长尽可能的靠近T/2,同上面。当然,有了0-1背包问题的基础,这种类似0-1背包问题的题目也是小儿科了,下面是AC代码“

#include <iostream>
#include <cstring>
using namespace std;
#define Max 666
    int main()
    {
        int s[5];
        int dp[Max][Max];
        int res=0;
        int a[Max];
        memset(dp,0, sizeof(dp));
        memset(a,0, sizeof(a));
        for(int i=1;i<=4;i++)
        {
            cin>>s[i];
        }
        int sum;
        for(int i=1;i<=4;i++)
        {
            sum=0;
            for(int j=1;j<=s[i];j++)
            {
                cin>>a[j];
                sum+=a[j];
            }

            for(int j=1;j<=s[i];j++)
            {
                for(int k=1;k<=sum/2;k++)
                {
                    if(k<a[j]) //如果
                    {
                        dp[j][k]=dp[j-1][k]; //前j件物品放入容量为k的背包中
                    }
                    else
                    {
                        dp[j][k]=max(dp[j-1][k],dp[j-1][k-a[j]]+a[j]);
                    }
                }
            }
            res+=max(dp[s[i]][sum/2],sum-dp[s[i]][sum/2]);
        }
        cout<<res<<endl;
        return 0;
    }

2020-4-3更新一波,这种题目怎么少得了爆搜呢,毕竟暴力出奇迹。

此题的时间很宽裕,也可能是数据太水了,反正最后10个点都过了。

思路:枚举1—s[i]的所有题目,分别加到左脑和右脑,枚举完毕以后选出左右脑最大值中最小的那一个,展开来看就是一颗二叉树了,我们只需要套用一下二叉树的先序遍历即可。AC代码~

#include <iostream>
#include <cstring>
using namespace std;
#define Max 666
int lef=0,rig=0; //定义左脑和右脑
int Min=99999;
void dfs(int a[],int begin,int end,int &res);
    int main()
    {
        int s[5];
        int a[Max];
        for(int i=1;i<=4;i++)
        {
            cin>>s[i];
        }
        int sum=0;
        int res;
        for(int i=1;i<=4;i++)
        {
            memset(a,0, sizeof(a));
            res=Min;
            for(int j=1;j<=s[i];j++)
            {
                cin>>a[j];
            }
            dfs(a,1,s[i],res);
            sum+=res;

        }
        cout<<sum<<endl;
        return 0;
}


    void dfs(int a[],int begin,int end,int &res)
    {
        if(begin==end+1)
        {
            res=min(res,max(lef,rig));
            return ;
        }
        else
        {

          lef+=a[begin];//选择左脑
          dfs(a,begin+1,end,res);
          lef-=a[begin]; //不选择左脑
          rig+=a[begin];//选择右脑
          dfs(a,begin+1,end,res);
          rig-=a[begin];
       }

    }
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值