HDU 5818 Joint Stacks(模拟 || 优先队列 || 左式堆)

8 篇文章 0 订阅
2 篇文章 0 订阅

题目链接:点击打开链接

题目大意:给定T个操作,A栈和B栈,操作包含三种,一种是push,即向A栈或B栈中加入一个新元素,一种是pop即输出A栈或B栈的栈顶元素,最后一个是merge,即合并两个栈,并保留第一个栈清空第二个栈(即如果输入merge B A为保留B,清空A)。

题目解析:比赛的时候自己想到去模拟一下,时间复杂度肯定没问题,就是调试可能会耗点时间,于是让队友现行上模板用左式堆过掉了,比赛之后刷一刷其他人的博客发现三个优先队列也是可以的,校内的另一支队伍用双向链表也过了,不过道理和优先队列是差不多的。直接给代码吧,题意很清晰,没啥难点。


先上一个我赛后自己写的一个模拟吧,就把所有push都记录下来,设立一个A、B标记,用于标记A栈pop的位置和B栈pop的位置,C记录一下合并的时候从哪个位置开始是都属于某一个栈的,D是记录是哪一个栈。

//模拟法
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define LL __int64
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pair pair<int,int>
const int INF = 0x3f3f3f3f;
using namespace std;

struct node{
    int choose;
    bool is_pop;
    int val;
}arr[100005];
int T,x,tot;
char op[15],chos[5];

int main(){
    int cas = 1,A,B,C,D;
    while(~scanf("%d",&T) && T){
        printf("Case #%d:\n",cas++);
        tot = A = B = D = 0;
        C = -1;
        for(int l=0;l<T;l++){
            scanf("%s",op);
            if(op[1] == 'u'){
                scanf("%s %d",chos,&x);
                arr[tot].is_pop = false;
                arr[tot].choose = (chos[0]=='A')?1:2;
                arr[tot].val = x;
                if(chos[0] == 'A') //记录A、B栈的栈顶
                    A = tot;
                else
                    B = tot;
                tot += 1;
            }
            else if(op[1] == 'o'){
                scanf("%s",chos);
                if(chos[0] == 'A'){
                    printf("%d\n",arr[A].val);//输出栈顶,并且寻找下一个栈顶
                    arr[A].is_pop = true;
                    for(int i=A;i>=0;i--){
                        if(C == -1){   //如果之前合并过
                            if(arr[i].choose == 1 && arr[i].is_pop == false){
                                A = i;
                                break;
                            }
                        }
                        else{
                            if(i <= C){
                                if(D == 1){
                                    if(arr[i].is_pop == false){
                                        A = i;
                                        break;
                                    }
                                }
                            }
                            else{
                                if(arr[i].choose == 1 && arr[i].is_pop == false){
                                    A = i;
                                    break;
                                }
                            }
                        }
                    }
                }
                else{
                    printf("%d\n",arr[B].val);
                    arr[B].is_pop = true;
                    for(int i=B;i>=0;i--){
                        if(C == -1){
                            if(arr[i].choose == 2 && arr[i].is_pop == false){
                                B = i;
                                break;
                            }
                        }
                        else{
                            if(i <= C){
                                if(D == 2){
                                    if(arr[i].is_pop == false){
                                        B = i;
                                        break;
                                    }
                                }
                            }
                            else{
                                if(arr[i].choose == 2 && arr[i].is_pop == false){
                                    B = i;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            else if(op[1] == 'e'){
                scanf("%s %s",op,chos);
                if(op[0] == 'A'){ //合并之后要重新计算栈顶
                    D = 1;
                    for(int i=tot-1;i>=0;i--){
                        if(arr[i].is_pop == false){
                            A = i;
                            break;
                        }
                    }
                }
                else{
                    D = 2;
                    for(int i=tot-1;i>=0;i--){
                        if(arr[i].is_pop == false){
                            B = i;
                            break;
                        }
                    }
                }
                C = tot - 1;
            }
        }
    }
    return 0;
}


之后就是比赛的时候写的左式堆了

//左式堆
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
using namespace std;

template <typename Comparable>
class LeftistHeap
{
public:
    LeftistHeap():root(NULL)
    {}
    LeftistHeap(const LeftistHeap &rhs)
    {
        *this = rhs;
    }
    ~LeftistHeap()
    {
        clear();
    }
    void push(const Comparable &x)
    {
        root = merge(new LeftistNode(x), root);
    }
    bool empty() const
    {
        return root == NULL;
    }
    const Comparable& top() const
    {
        return root->element;
    }
    void pop()
    {
        if(empty())
            return;
        LeftistNode* oldroot = root;
        root = merge(root->left, root->right);
        delete oldroot;
    }
    void pop(Comparable &minItem)
    {
        minItem = top();
        pop();
    }
    void clear()
    {
        reclaimMemory(root);
        root = NULL;
    }
    void merge(LeftistHeap &rhs)
    {
        if(this == &rhs)
            return;
        root = merge(root, rhs.root);
        rhs.root = NULL;
    }
    const LeftistHeap& operator=(const LeftistHeap &rhs)
    {
        if(this != &rhs)
        {
            clear();
            root = clone(rhs.root);
        }
        return *this;
    }
private:
    struct LeftistNode
    {
        Comparable    element;
        LeftistNode    *left;
        LeftistNode    *right;
        int            npl;
        LeftistNode(const Comparable &e, LeftistNode *l = NULL,
            LeftistNode *r = NULL, int n = 0)
            :element(e), left(l), right(r), npl(n)
        {}
    };
    LeftistNode *root;
    LeftistNode* merge(LeftistNode *h1, LeftistNode *h2)
    {
        if(h1 == NULL)
            return h2;
        if(h2 == NULL)
            return h1;
        if(h1->element < h2->element)
            return merge1(h1, h2);
        else
            return merge1(h2, h1);
    }
    LeftistNode* merge1(LeftistNode *h1, LeftistNode *h2)
    {
        if(h1->left == NULL)
            h1->left = h2;
        else
        {
            h1->right = merge(h1->right, h2);
            if(h1->left->npl < h1->right->npl)
                swapChildren(h1);
            h1->npl = h1->right->npl + 1;
        }
        return h1;
    }
    void swapChildren(LeftistNode *t)
    {
        LeftistNode *tmp = t->left;
        t->left = t->right;
        t->right = tmp;
    }
    void reclaimMemory(LeftistNode *t)
    {
        if(t != NULL)
        {
            reclaimMemory(t->left);
            reclaimMemory(t->right);
            delete t;
        }
    }
    LeftistNode *clone(LeftistNode *t) const
    {
        if(t == NULL)
            return NULL;
        else
            return new LeftistNode(t->element, clone(t->left), clone(t->right));
    }
};

struct info
{
    int t,x;
    info(){}
    info(int a,int b):t(a),x(b){}
    bool operator < (const info &a)const
    {
        return t > a.t;
    }
};

LeftistHeap<info> A,B;

int main()
{
    int n;
    int cas = 0;
    while(~scanf("%d",&n) && n)
    {
        A.clear();
        B.clear();
        printf("Case #%d:\n",++cas);
        int x;
        char op[10];
        char stk[10],stk2[10];
        for(int i = 0 ; i < n ; i++)
        {
            scanf("%s",op);
            if(op[1] == 'u') //push
            {
                scanf("%s %d",stk,&x);
                if(stk[0] == 'A')
                    A.push(info(i,x));
                else
                    B.push(info(i,x));
            }
            else if(op[1] == 'o') //pop
            {
                scanf("%s",stk);
                if(stk[0] == 'A')
                {
                    printf("%d\n",A.top().x);
                    A.pop();
                }
                else
                {
                    printf("%d\n",B.top().x);
                    B.pop();
                }
            }
            else //merge
            {
                scanf("%s %s",stk,stk2);
                if(stk[0] == 'A') //B to A
                {
                    A.merge(B);
                }
                else //A to B
                {
                    B.merge(A);
                }
            }
        }
    }

    return 0;
}

<span style="font-family: Arial, Helvetica, sans-serif; white-space: normal; background-color: rgb(255, 255, 255);">//优先队列</span>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define LL __int64
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pair pair<int,int>
const int INF = 0x3f3f3f3f;
using namespace std;

typedef pair<int,int> pii;
priority_queue<pii> com;
priority_queue<pii> a;
priority_queue<pii> b;

int main(int argc, char const *argv[])
{
    //IN;

    int n; int ca = 1;
    while(scanf("%d", &n) != EOF && n)
    {
        printf("Case #%d:\n", ca++);
        while(!a.empty()) a.pop();
        while(!b.empty()) b.pop();
        while(!com.empty()) com.pop();

        int time_cnt = 0;

        while(n--) {
            char op[10]; char aim;
            scanf("%s %c", op,&aim);
            if(op[1] == 'u') {
                int x; scanf("%d", &x);
                if(aim == 'A') {
                    a.push(make_pair(time_cnt++, x));
                } else {
                    b.push(make_pair(time_cnt++, x));
                }
            }
            else if(op[1] == 'o') {
                if(aim == 'A') {
                    if(!a.empty()) {
                        pii x = a.top(); a.pop();
                        printf("%d\n", x.second);
                    } else {
                        pii x = com.top(); com.pop();
                        printf("%d\n", x.second);
                    }
                } else {
                    if(!b.empty()) {
                        pii x = b.top(); b.pop();
                        printf("%d\n", x.second);
                    } else {
                        pii x = com.top(); com.pop();
                        printf("%d\n", x.second);
                    }
                }
            }
            else {
                char tmp[10]; gets(tmp);
                while(!a.empty()) {
                    pii x = a.top();
                    a.pop();
                    com.push(x);
                }
                while(!b.empty()) {
                    pii x = b.top();
                    b.pop();
                    com.push(x);
                }
            }
        }
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于HDU4546问题,还可以使用优先队列(Priority Queue)来解决。以下是使用优先队列的解法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列解决HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个解法对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值