c++算法基础必刷题目——贪心+公式推导

公式推导

1、国王的游戏

NC16561 国王的游戏

题目描述

  恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入描述:

第一行包含一个整数 n ,表示大臣的人数。
第二行包含两个整数 a 和 b ,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n 行,每行包含两个整数 a 和 b ,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出描述:

一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

示例1

输入
3
1 1
2 3
7 4
4 6

输出
2

说明

按 1 、 2 、 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 1 、 3 、 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 2 、 1 、 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 2 、 3 、 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 ;
按 3 、 1 、 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 3 、 2 、 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 。
因此,奖赏最多的大臣最少获得 2 个金币,答案输出 2 。

备注:

对于 20%的数据,有 1≤ n≤ 10,0 < a,b < 8 ;
对于 40%的数据,有 1≤ n≤20,0 <a,b<8 ;
对于 60%的数据,有 1≤ n≤100 ;
对于 60%的数据,保证答案不超过 109
对于 100%的数据,有 1 ≤ n ≤1,000,0 < a,b < 10000 。

解题思路:
1、贪心思想,假如有3个大臣,左右手的数字如下

左手右手
A1A2
B1B2
C1C2

那么为了使得第三位大臣奖赏尽可能少,那么该怎么做呢,如果把A调到第三位,那么奖赏是A1*B1*C1/A1*A2,如果把B调到第三位,那么奖赏是A1*B1*C1/B1*B2,如果把C调到第三位,那么奖赏是A1*B1*C1/C1*C2,可以发现,左右手数字的乘积越大,那么奖赏越小,这个做法是最优的

2、所有的大臣都按照左右手乘积升序排序,那么我们来验证正确性,假如A1*A1<B1*B2<C1*C2,那么排序将是ABC,此时解是最优的,因为无论再交换任意两个大臣的位置,都会使得最大奖赏更大,假如B和C交换位置,那么第二位大臣奖赏减少,第三位大臣奖赏增加,但是此时第三位大臣的奖赏一定比交换之前第二位大臣的奖赏高,那么就说明了此时是最优的排序

3、因为数据量庞大,所以需要使用大数乘法与大数除法

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
string mult(string s1,string s2){//大数乘法
    vector<int> v;
    for(int i=s1.size()-1;i>=0;i--){
        for(int j=s2.size()-1;j>=0;j--){
            if(v.size()<=s1.size()-1-i+s2.size()-1-j){
                v.push_back(0);
            }
            v[s1.size()-1-i+s2.size()-1-j]+=(s1[i]-'0')*(s2[j]-'0');
        }
    }
    string s3;
    for(int i=0;i<v.size();i++){
        if(i==v.size()-1&&v[i]/10!=0){
            v.push_back(0);
        }
        v[i+1]+=v[i]/10;
        v[i]%=10;
        s3+=v[i]+'0';
    }
    reverse(s3.begin(),s3.end());
    return s3;
}
string div(string s1,long long s2){//大数除法
    string s3;
    int flag=0;
    long long sum=0;
    for(int i=0;i<s1.size();i++){
        sum*=10;
        sum+=s1[i]-'0';
        if(sum/s2!=0){
            flag=1;
        }
        if(flag){
            s3+=sum/s2+'0';
        }
        sum%=s2;
    }
    return s3;
}
bool cmp(vector<string> s1,vector<string> s2){
    if(mult(s1[0],s1[1]).size()==mult(s2[0],s2[1]).size()){//字符串长度相同则比较大小
        return mult(s1[0],s1[1])<mult(s2[0],s2[1]);
    }
    return mult(s1[0],s1[1]).size()<mult(s2[0],s2[1]).size();//长度不同比较长度
}
signed main(){
    int n;
    cin>>n;
    vector<vector<string>> v;
    for(int i=0;i<=n;i++){
        string s1,s2;
        cin>>s1>>s2;
        v.push_back({s1,s2});
    }
    sort(v.begin()+1,v.end(),cmp);//贪心排序
    string ans="0";
    string s1=v[0][0];
    for(int i=1;i<=n;i++){
        if(ans.size()<div(s1,stoi(v[i][1])).size()||(ans.size()==div(s1,stoi(v[i][1])).size()&&ans<div(s1,stoi(v[i][1])))){
            ans=div(s1,stoi(v[i][1]));//取最优解
        }
        s1=mult(s1,v[i][0]);
    }
    cout<<ans<<endl;
}

2、Protecting the Flower

NC25043 Protecting the Flower

题目描述

  Farmer John went to cut some wood and left N (2 ≤ N ≤ 100,000) cows eating the grass, as usual. When he returned, he found to his horror that the cluster of cows was in his garden eating his beautiful flowers. Wanting to minimize the subsequent damage, FJ decided to take immediate action and transport each cow back to its own barn.
  Each cow i is at a location that is Ti minutes (1 ≤ Ti ≤ 2,000,000) away from its own barn. Furthermore, while waiting for transport, she destroys Di (1 ≤ Di ≤ 100) flowers per minute. No matter how hard he tries, FJ can only transport one cow at a time back to her barn. Moving cow i to its barn requires 2 × Ti minutes (Ti to get there and Ti to return). FJ starts at the flower patch, transports the cow to its barn, and then walks back to the flowers, taking no extra time to get to the next cow that needs transport.
  Write a program to determine the order in which FJ should pick up the cows so that the total number of flowers destroyed is minimized.

输入描述:

Line 1: A single integer N
Lines 2…N+1: Each line contains two space-separated integers, Ti and Di, that describe a single cow’s characteristics

输出描述:

Line 1: A single integer that is the minimum number of destroyed flowers

示例1

输入
6
3 1
2 5
2 3
3 2
4 1
1 6

输出
86

解题思路:
1、题目意思:有很多头牛,这些牛每分钟破坏Di朵花,把它们拉回牛棚可以阻止牛牛破坏花朵,拉回去再回来一共需要要 2*Ti 分钟,问按什么顺序拉牛回牛棚才能使得花朵被破坏得最少,最少为多少朵

2、如果有两头牛,属性如下:

时间花朵
T1D1
T2D2

那么应该先拉哪头牛呢?很明显,假如拉第一头,那么总花费为T1*D2,假如拉第二头,那么总花费为T2*D1,判断哪个花费小先拉哪个即可,同样地,假如有三头牛,先拉哪头也可以这样判断

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
bool cmp(vector<int> v1,vector<int> v2){
    return v1[0]*v2[1]<v2[0]*v1[1];
}
signed main(){
    int n;
    cin>>n;
    int ans=0;
    vector<vector<int>> v;
    for(int i=0;i<n;i++){
        int b,c;
        cin>>b>>c;
        v.push_back({b*2,c});
    }
    sort(v.begin(),v.end(),cmp);
    int t=0;
    for(int i=0;i<n;i++){
        ans+=t*v[i][1];
        t+=v[i][0];
    }
    cout<<ans<<endl;
}

是不是很简单呢?

刚接触肯定会觉得难,多些做题多些用,熟悉了就容易了,兄弟萌,加油!!!

文章尚有不足,感谢您的指正

感谢观看,点个赞吧

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧林墨烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值