北大大数据机试题

http://bailian.openjudge.cn/dsj2017xly/

下面是G题,正好试一下优先队列

G:双队列

总时间限制:
1000ms
内存限制:
65536kB

描述

系统A用来维护客户。每个客户的id用一个正整数K来表示,当客户进入系统时用P来表示此用户的优先度。这个系统有以下请求

0  系统停止运行
1 K P  优先度为P的客户K进入系统
2 找到优先度最高的客户,然后此客户离开系统
3 找到优先度最低的客户,然后此客户离开系统

输入
每行包括一个请求,最后一行包括一个停止请求(代码0)。对于添加客户请求(代码1),优先度都是唯一的。客户的表示K小于106,优先度P小于107,一个客户可能会被添加多次,每次的优先度可能不同。
输出
对于每个请求2和3,程序必须输出一行。这行包括此请求中找到客户的id。如果系统中没有客户,输出0
样例输入

2
1 20 14
1 30 3
2
1 10 99
3
2
2
0

样例输出

0
20
30
10
0

思路:

开始想着用两个优先队列做,分别定义一个最大堆和一个最小堆,但是这样出了问题,因为如果弹出最大堆的元素,那么该元素在最小堆中仍然存在,这与题意是不相符的。所以只好用题目中所说的“双队列”了。
下面是错误的两个优先队列的代码,虽然与本题不符,但是也把定义优先队列的方法记录下来,如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cstdio>
using namespace std;
struct client{//重载运算符,使他成为最小堆,
    int id;//父节点元素都比子节点大,根节点是最大值
    int pri;
    client(int i, int p){ //构造方法
        id = i;
        pri = p;
    }
    //重载运算符,定义<
    bool operator < (const client &a) const{  //这个地方的const,必须要加
        if (pri < a.pri) return true;
        else return false;
    }
};
struct client2{  //重载运算符,使他成为最小堆,
    int id;     //父节点元素都比子节点小,根节点是最小值
    int pri;
    client2(int i, int p){
        id = i;
        pri = p;
    }
    bool operator < (const client2 &a) const{
        if (pri < a.pri) return false;
        else return true;
    }
};
int main(){
    //按照这个题目,定义两个优先队列是错误的,因为
    //如果选择2,就会从最大堆里弹出,但是该用户仍然存在在最小堆里
    //所以应该用双向队列
    priority_queue<client> maxx;  //定义一个最大堆
    priority_queue<client2> minn; //定义一个最小堆
    int p, k, quest;
    while (true){
        cin >> quest;
        if (quest == 0) break;
        if (quest == 1) {
            cin >> k >> p;
            client c(k, p);
            client2 d(k, p);
            minn.push(d);
            maxx.push(c);
        }
        if (quest == 2){  //控制最大堆
            if (maxx.empty()) cout << "0" << endl;
            else {
                cout << maxx.top().id << endl;
                maxx.pop();
            }
        }
        if (quest == 3){  //控制最小堆
            if (minn.empty()) cout << "0" << endl;
            else {
                cout << minn.top().id << endl;
                minn.pop();
            }
        }

    }
    return 0;
}

D:特殊密码锁
总时间限制: 1000ms 内存限制: 1024kB
描述
有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。

然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。

当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。

输入
两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。
输出
至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。
样例输入
011
000
样例输出
1

思路:

这个题,开始我想着因为n才30,直接深度优先搜索算了,应该不会超时,但是看了一下其他人的题解,发现原来直接贪心算法就可以。从第一个位置开始,如果不同,就按下第二个的按钮,这样就将n个元素的问题转换为n-1个,然后依次这样做。(下面的代码还没有编译运行)

#include "stdafx.h"
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include "stdio.h"
using namespace std;
int main() {
    char a1[30];
    char a2[30];
    int i = 0;
    while (true) {
        scanf("%c", &a1[i++]);
        if (a1[i - 1] == '\n') break;
    }
    int j = 0; 
    while (true) {
        scanf("%c", &a2[j++]);
        if (a2[j - 1] == '\n') break;
    }
    int ans = 0;
    for (int k = 0; k < i; k++) {
        if (k == i - 1) {
            if (a1[k] != a2[k])  cout << "impossible" << endl;
            else cout << ans << endl;
        }
        if (a1[k] == a2[k]) continue;
        else {
            a1[k + 1] ^= 1;  //异或  a1[k+1] = 1 - a1[k+1]
            a1[k] ^= 1;
            a1[k + 2] ^= 1;
            ans++;
        }
    }


}
发布了56 篇原创文章 · 获赞 49 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/IBelieve2016/article/details/74535454