UVA ~ 1598 ~ Exchange (优先队列 + 模拟)

题意:你的任务是为交易所设计一个订单处理系统。要求支持以下3种指令。

□ BUY p q:有人想买,数量为p,价格为q

□ SELL p q:有人想卖,数量为p,价格为q

□ CANCEL i:取消第i条指令对应的订单(输入保证该指令是BUY或者SELL)

交易规则如下: 对于当前买订单,若当前最低卖价(ask price) 低于当前出价,则发生交易;对于当前卖订单,若当前最高买价(bid price)高于当前价格,则发生交易。发生交易时,按供需物品个数的最小值交易。交易后,需修改订单的供需物品个数。当出价或者价格相同时,按订单产生的先后顺序发生交易。输入输出细节请参考原题。

提示: 本题是一个不错的优先队列练习题。 以上解释为COPY自算法竞赛入门。

补充一下:大家按生活中的常理去理解这个题就是对的。物品只有一种。如果现在有一条BUY的指令,我们肯定要买最便宜的啊(如果能买得起),如果现在现在是一条SELL的指令,我们的东西价格便宜,肯定出价高者先得啊(如果他们能买得起)。

输出格式为:对于当前指令,如果发生交易,输出“TRADE %d %d”,第一个%d此次交易的数量,第二个%d表示此次交易的价格(①如果当前指令是BUY,那么就是卖的价格,因为人家卖10元你花100元去买,那恐怕不是傻子哦 ②如果当前指令是SELL,那么就是买的出价,因为人家花100元买你10元的东西,你还不抓住机会,血赚一波)。每个指令后面输出一个:“QUOTE %d %d - %d %d”,前两个%d表示最高出价(BUY)的那【些】订单的数量、出价,后两个%d表示价格最低(SELL)的那【些】订单的数量、出价。(如果有几个订单都价格都为10,输出这几个订单数量和)

如果没有买的订单,价格数量都认为是0,如果没有卖的订单,价格认为99999,数量认为0。

坑点:可能对某一条指令取消两次!!!比如uDebug中的开始这部分数据:

4042
SELL 186 297
SELL 235 203
CANCEL 1
SELL 32 184
CANCEL 2
SELL 172 241
SELL 54 200
CANCEL 4
CANCEL 4
CANCEL 1

思路:首先保存输入的订单消息,用一个优先队列保存BUY的信息(出价高的优先,相等指令编号小的优先),另外一个优先队列保存SELL的信息(价格低的优先,相等指令编号小的优先)。我们在用两个map<int,int>:价格对应总数量,保存价格为x的数量,一个表示BUY的信息,一个表示SELL的信息。发生交易时,订单中和map和优先队列中对应的东西减少,然后输出此次交易信息。如果只有买卖,就好了,但是还有取消操作,所以我们需要开一个标记数组vis表示该订单有没有被取消,如果被取消了,map对应的东西需要进行对应减少。


AC代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 5;
struct Node
{
    int cost, num, id;
    string op;
    Node () {}
    Node (int _id, int _num, int _cost, string _op):
        id(_id), num(_num), cost(_cost), op(_op) {}
    bool operator < (const Node& that) const
    {
        if (cost != that.cost) return that.cost > cost;
        return that.id < id ;
    }
    bool operator > (const Node& that) const
    {
        if (cost != that.cost) return that.cost < cost;
        return that.id < id;
    }
};
int n;
Node IN[MAXN];//输入订单
bool vis[MAXN];//指令是否被取消
priority_queue<Node> buy;//买列表
priority_queue<Node, vector<Node>, greater<Node> > sell;//卖列表
map<int, int> _buy;//买的价格对应数量
map<int, int> _sell;//卖价格对应数量
void init()
{
    memset(vis, 0, sizeof(vis));
    _buy.clear(); _sell.clear();
    while (!buy.empty()) buy.pop();
    while (!sell.empty()) sell.pop();
    _buy[0] = 0; _sell[99999] = 0;
    buy.push(Node(MAXN, 0, 0, ""));
    sell.push(Node(MAXN, 0, 99999, ""));
}
void work(string str)
{
    while (sell.top().cost <= buy.top().cost)//可以交易
    {
        if (buy.size() == 1 || sell.size() == 1) break;
        if (vis[buy.top().id]) { buy.pop(); continue; }//被取消
        if (vis[sell.top().id]) {  sell.pop(); continue; }//被标记
        Node s = sell.top(), b = buy.top();
        sell.pop(); buy.pop();
        int num = min(s.num, b.num);
        b.num -= num; s.num -= num;
        IN[b.id].num -= num; IN[s.id].num -= num;//订单数减少
        _buy[b.cost] -= num; _sell[s.cost] -= num;
        if (s.num) sell.push(s);//还有剩余
        if (b.num) buy.push(b);
        if (str == "BUY") printf("TRADE %d %d\n", num, s.cost);
        if (str == "SELL") printf("TRADE %d %d\n", num, b.cost);
    }
    while (sell.size() > 1 && vis[sell.top().id]) sell.pop();//如果队首是被取消的订单
    while (buy.size() > 1 && vis[buy.top().id]) buy.pop();//如果队首是被取消的订单
}
int main()
{
    bool has_out = false;
    while (~scanf("%d", &n))
    {
        init();
        if (has_out) printf("\n");
        else has_out = true;
        for (int i = 1; i <= n; i++)
        {
            string str; cin >> str;
            if (str == "BUY")
            {
                int p, q; scanf("%d%d", &p, &q);
                IN[i] = Node(i, p, q, str);//保存输入信息
                _buy[q] += p;
                buy.push(Node(i, p, q, str));//插入优先队列
            }
            if(str == "SELL")
            {
                int p, q; scanf("%d%d", &p, &q);
                IN[i] = Node(i, p, q, str);//保存输入信息
                _sell[q] += p;
                sell.push(Node(i, p, q, str));//插入优先队列
            }
            if (str == "CANCEL")
            {
                int id; scanf("%d", &id);
                //没有被取消
                if (IN[id].op == "BUY" && !vis[id]) _buy[IN[id].cost] -= IN[id].num;
                if (IN[id].op == "SELL" && !vis[id]) _sell[IN[id].cost] -= IN[id].num;
                vis[id] = true;//标记为取消
            }
            work(str);
            printf ("QUOTE %d %d - %d %d\n", _buy[buy.top().cost], buy.top().cost, _sell[sell.top().cost], sell.top().cost);
        }
    }
    return 0;
}
/*
11
BUY 100 35
CANCEL 1
BUY 100 34
SELL 150 36
SELL 300 37
SELL 100 36
BUY 100 38
CANCEL 4
CANCEL 7
BUY 200 32
SELL 500 30
*/


附一份当时水过去的代码,哈哈哈

采用了一种很暴力的解法,即取消操作:是通过找到优先队列中对应的那个订单删掉,之前pop的那些订单先存到一个vector中,然后在放回优先队列,就实现了取消操作。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 5;
struct Buy
{
    int cost, num, id;
    Buy (int _num, int _cost, int _id): num(_num), cost(_cost), id(_id) {}
    bool operator < (const Buy& that) const
    {
        if (cost != that.cost) return that.cost > cost;
        return that.id < id ;
    }
};
struct Sell
{
    int price, num, id;
    Sell (int _num, int _price, int _id): num(_num), price(_price), id(_id) {}
    bool operator < (const Sell& that) const
    {
        if (price != that.price) return that.price < price;
        return that.id < id;
    }
};
int n;
priority_queue<Buy> buy;
priority_queue<Sell> sell;
map<int, int> _buy;//price num
map<int, int> _sell;//price num
void init()
{
    _buy.clear(); _sell.clear();
    while (!buy.empty()) buy.pop();
    while (!sell.empty()) sell.pop();
    _buy[0] = 0; _sell[99999] = 0;
    buy.push(Buy(0, 0, MAXN));
    sell.push(Sell(0, 99999, MAXN));
}
void work(string str)
{
    while (sell.top().price <= buy.top().cost)
    {
        if (sell.size() == 1 || buy.size() == 1) break;
        Sell s = sell.top(); Buy b = buy.top();
        sell.pop(); buy.pop();
        int num = min(s.num, b.num);
        s.num = s.num - num; b.num = b.num - num;
        _buy[b.cost] -= num; _sell[s.price] -= num;
        if (s.num) sell.push(s);
        if (b.num) buy.push(b);
        if (str == "BUY") printf("TRADE %d %d\n", num, s.price);
        if (str == "SELL") printf("TRADE %d %d\n", num, b.cost);
    }
}
void Cancel(int id)
{
    bool flag = false;
    vector<Buy> v1;
    while (buy.size() != 1)
    {
        if (buy.top().id == id)
        {
            flag = true;
            _buy[buy.top().cost] -= buy.top().num;
            buy.pop(); break;
        }
        v1.push_back(buy.top()); buy.pop();
    }
    vector<Sell> v2;
    while (sell.size() != 1 && !flag)
    {
        if (sell.top().id == id)
        {
            _sell[sell.top().price] -= sell.top().num;
            sell.pop(); break;
        }
        v2.push_back(sell.top()); sell.pop();
    }
    for (auto i: v1) buy.push(i);
    for (auto i: v2) sell.push(i);
}
int main()
{
    bool has_out = false;
    while (~scanf("%d", &n))
    {
        init();
        if (has_out) puts("");
        has_out = true;
        for (int i = 1; i <= n; i++)
        {
            string str; cin >> str;
            if (str == "BUY")
            {
                int p, q; scanf("%d%d", &p, &q);
                _buy[q] += p;
                buy.push(Buy(p, q, i));
            }
            if(str == "SELL")
            {
                int p, q; scanf("%d%d", &p, &q);
                _sell[q] += p;
                sell.push(Sell(p, q, i));
            }
            if (str == "CANCEL")
            {
                int id; scanf("%d", &id);
                Cancel(id);
            }
            work(str);
            printf ("QUOTE %d %d - %d %d\n", _buy[buy.top().cost], buy.top().cost
                    , _sell[sell.top().price], sell.top().price);
        }
    }
    return 0;
}
/*
11
BUY 100 35
CANCEL 1
BUY 100 34
SELL 150 36
SELL 300 37
SELL 100 36
BUY 100 38
CANCEL 4
CANCEL 7
BUY 200 32
SELL 500 30
*/







评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值