贪心&栈&队列&优先队列

E - 均分纸牌

题意:给出一个长度为n的序列,序列从1开始编号,序列上的数代表这个位置上的权值,且保证所有位置上的权值之和为n的倍数。操作如下:在第一个位置上的数的权值,只能往第二个位置上移动,第n个位置上的数的权值只能往第n-1的数移动,其余左右都可。要求找到一种移动方法,用最少的移动次数使得每个位置上的权值一样。

思路:其实这道题就是贪心。比如序列: 9, 8, 17, 6,这个平均数就是10,从1位置开始,需要从右边借一个,而右边本身也差两个,最后变成差三个,那为什么不3位置直接给2位置3个,然后2位置给1两个,这样两次操作前两个数都满足了,而不是3给2一个,2给1一个,3给2两个,这样操作数就变成3了。所以只需要从左到右遍历数组,把遍历到的位置都变成aver,同时后面那个数减上(aver - a[i] ),这个公式对于,9 8 or 8 17都成立。而且题中给的交换顺序,其实没有用。

#include<iostream>
using namespace std;
typedef long long ll;
const int MAX = 1e4 + 10;
ll n, a[MAX];
int main(){
    ios :: sync_with_stdio( false );
    cin.tie( NULL );
    cin >> n;
    ll sum = 0;
    for( int i = 0; i < n; i++ ){
        cin >> a[i];
        sum += a[i];
    }
    ll aver = sum / n;
    ll cnt = 0;
    for( int i = 0; i < n - 1; i++ ){
        if( a[i] != aver ){
            ++cnt;
            a[i + 1] -= aver - a[i];// ‘-’就很有灵魂了
            a[i] = aver;
        }
    }
    cout << cnt << endl;
    return 0;
}

D - Yogurt factory 奶酪工厂

题意:生产一种物品的单价每周都在变化,而且每周都有必须的生产量,但是可以无限量无限时的保存生产的东西,但是每保存一单位的物品,每周就要多S¥(也就是每周可以多生产),问这段时间里完成任务的最小代价。

思路:这道题其实就是问,每周到底要生产多少,那就要看在这周生产是不是更便宜,即使加上存储费用。第一周当然要把必须生产的东西生产完,同时考虑是不是要多生产,而且这时是单价最小的时候,第二周有两种价钱,第一种是:最小的单价+S,第二种:这周的本身单价。选择这两种中最小的=min( 最小的+S,这周本身)。同理与第三周,所以有一种递推的感觉,我当时不知道递推找最小,就一直在疑惑到底哪个是最小啊...

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAX = 1e4 + 10;
const int INF = 0x3f3f3f3f;
ll n, s, c[MAX];
int main(){
    ios :: sync_with_stdio( false );
    cin.tie( NULL );
    cin >> n >> s;
    ll minn = INF;
    ll sum = 0;
    ll c, y;
    for( int i = 0;i < n; i++ ){
        cin >> c >> y;
        minn = min( minn + s, c );//关键点
        sum += minn * y;
    }
    cout << sum << endl;
    return 0;
}

C - 蜗牛旅游

题意:给定一个长度为n的数组,找出最长不同子序列,问此序列的长度。

思路:其实这就是用队列直接进行模拟就行。用一个set建立一个集合用于记录哪些数已经进入队列,用一个queue模拟过程。只要这个数没有在队列中,就压队,每次压入就用max记录一次队列的最大长度;如果在队列中,就开始pop(包含这个数),同时要删除set集合中的数,以此来保证更新。然后再进行压入。最后输出maxx即可。

#include<iostream>
#include<algorithm>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
queue< ll > q;
set< ll > s;
ll n, num;
int main(){
    ios :: sync_with_stdio( false );
    cin.tie( NULL );
    cin >> n;
    ll maxx = -1;
    for( int i = 0; i < n; i++ ){
        cin >> num;
        if( !s.count( num )){
            s.insert( num );
            q.push( num );
            ll tp = q.size();
            maxx = max( maxx, tp );
        }
        else{
            while( 1 ){
                if( !q.empty() && q.front() != num ){
                    s.erase( q.front() );
                    q.pop();
                }
                if( !q.empty() && q.front() == num ){//注意以前出现过的这个数也要删除
                    q.pop();
                    q.push( num );
                    break;
                }
            }
        }
    }
    cout << maxx << endl;
    return 0;
}

B - Text Reverse

 题意:一种单词字符串:里面的单词都是翻转的,其中标点符号和单词算在一起,给出这种单词字符串,输出正常的字符串。

思路:其实就是使用栈来解决问题。然后就是注意具体实现。

#include<iostream>
#include<cstring>
#include<string>
#include<stack>
#include<vector>
#include<stdio.h>
using namespace std;
int n;
string s;
int main(){
    ios :: sync_with_stdio( false );
    cin.tie( NULL );
    cin >> n;
    cin.get();
    while( n-- ){
        stack< char > st;
        vector< char > v;
        int len;
        getline(cin,s);//注意输入有空格的时候要用getline( cin, s );
        int slen = s.length();
        for( int i = 0; i < slen; i++ ){
            if( s[i] != ' ' ){
                st.push( s[i] );
            }
            else{
                len = st.size();
                for( int i = 0; i < len; i++ ){
                    v.push_back( st.top() );
                    st.pop();
                }
                v.push_back( ' ' );
            }
        }
        len = st.size();
        for( int i = 0; i < len; i++ ){//注意细节,后面可能还有没有用完的
             v.push_back( st.top() );
                st.pop();
        }
        len = v.size();
        for( int i = 0; i < len; i++ ){
            cout << v[i];
        }
        cout << endl;
    }
    return 0;
}

总结:

对于贪心这次的感觉就是要从整体出发来思考,不要只局限与局部,以及从理论到代码的实现。

对于栈、队列、优先队列,其实就是要积累经验,看看这种条件适不适合这种数据结合。要记住他们常用的函数,易错点这些。

stack:

s.clear(); //清空
s.empty();  //判断stack是否为空,为空返回true,否则返回false
s.size();   //返回stack中元素的个数
s.pop();    //删除栈顶元素,但不返回其值
s.top();    //返回栈顶元素的值,但不删除此元素
s.push(item);   //在栈顶压入新元素item

queue & priority_queue:

while (!q.empty()) q.pop(); //注意queue & priority_queue没有清空函数
q.empty();  //判断队列是否为空
q.size();   //返回队列长度
q.push(item);   //对于queue,在队尾压入一个新元素
//对于priority_queue,在基于优先级的适当位置插入新元素
 
//queue only:
q.front();  //返回队首元素的值,但不删除该元素
q.back();   //返回队尾元素的值,但不删除该元素
 
//priority_queue only:
q.top();    //返回具有最高优先级的元素值,但不删除该元素

PS:

1、优先队列的本质是完全二叉树,可分为小根堆和大根堆。

2、优先队列的优先级设置:

对于node结构:priority_queue < node > q;

struct node{
    int r, c, t;
    node( int nr, int nc, int nt ){
        r = nr;
        c = nc;
        t = nt;
    }
    friend bool operator< ( node a, node b ){
        return a.t > b.t;
    }

};

对于int结构:priority_queue< int > p; // 默认是大根堆

priority_queue< int, vector< int >, less< int > > p; //默认是小根堆

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值