[刷题]算法竞赛入门经典(第2版) 6-9/UVa127 - "Accordian" Patience

题意:52张牌排一行,一旦出现任何一张牌与它左边的第一张或第三张“匹配”,即花色或点数相同,则须立即将其移动到那张牌上面,将其覆盖。能执行以上移动的只有压在最上面的牌。直到最后没有牌能向左移动。
注意细则:如果同时有多张牌都可以移动,你应该采取的策略是移动最左边可移动的牌。当一张牌既可以移动到左边第一张,又可以移动到左边第三张时,应移动到左边第三张上面。


代码:(Accepted,0.100s)

//UVa127 - "Accordian" Patience
//Accepted 0.100s
//#define _XIENAOBAN_
#include<iostream>
#include<cstdio>
#define NUM 52
#define BIAS 1
using namespace std;

struct card {
    char a, b;
    bool operator ==(card& that) {
        return a == that.a || b == that.b;
    }

};

struct stack {
    card st[NUM + 2], *p;
    void ini() {
        p = st + 1;
    }
    card& pop() {
        if (p != st) return *(p--);
        return *p;
    }
    card& top() {
        return *p;
    }
    void push(card& c) {
        *++p = c;
    }
    int size() {
        return p - st;
    }
    bool empty() {
        return p == st;
    }
}cards[NUM + 3];

struct list {
    stack *ls[NUM + 2];
    list() {
        for (int i(0);i < NUM + 1;++i)
            ls[i] = cards + i;
        ls[NUM + 1] = nullptr;
    }
    void erease(int n) {
        while (ls[n] != nullptr) {
            ls[n] = ls[n + 1];
            ++n;
        }
    }
    stack& operator [](int i) {
        if (i >= 0) return *ls[i];
        return *ls[0];
    }
};


int main()
{
#ifdef _XIENAOBAN_
#define gets(T) gets_s(T, 129)
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif

    cards[0].st[1].a = cards[0].st[1].b = 'X';          // 第0个stack的top里储存一个没用的card,使得没有一张卡片与之相等,以方便以后处理前两张左边没牌的牌;
    while ((cards[1].st[1].a = getchar()) != '#') {
        cards[1].st[1].b = getchar();
        getchar();
        for (int i(0);i < NUM + 3;++i) cards[i].ini();  // 每个stack里将都只有一张卡片,这个ini就是把top的指针指向1
        for (int i(2);i < NUM + 1;++i) {                // 数据全部直接作为top读取到stack里面
            cards[i].top().a = getchar();
            cards[i].top().b = getchar();
            getchar();
        }
        list pile;                                      //处理部分,直接模拟,懒得另写函数了
        int num;
        for (num = 2;&pile[num];) {                     // num从2开始,毕竟第一个数据怎么样也移动不了(接下来num再跳回1就懒得管他了)
            if (pile[num].top() == pile[num - 3].top()) {
                pile[num - 3].push(pile[num].pop());
                if (pile[num].empty()) pile.erease(num);
                num -= 3;
            }
            else if (pile[num].top() == pile[num - 1].top()) {
                pile[num - 1].push(pile[num].pop());
                if (pile[num].empty()) pile.erease(num);
                --num;
            }
            else ++num;
        }
        printf("%d pile", num - 1);
        if (num != 2) printf("s");
        printf(" remaining:");
        for (int i(1);i < num;++i) printf(" %d", pile[i].size());
        puts("");
    }
    return 0;
}

分析:差不多又是一遍过,而且只用了0.1s,竟然挤进了UVa本题Ranking的前20,虽然题目确实很简单就是了,还是开心的不行。
我的思路是安放52个栈,直接进行模拟操作。从第二张牌开始(毕竟第一张牌不可能向左移动)往下判断,直到到达末尾。
具体流程是,若当前牌可以左移,移之,并且下一个进行判断的牌还是它(因为左侧的都是已经完成的不可能再有可移动的牌了,所以无需重新从最左侧开始检索);反之此牌没法动了,则判断下一张牌。
感觉这不能叫遍历,毕竟期间会向左移动牌,应该算是迭代吧。
要注意的是输出格式!如下图所示,

6 piles remaining: 40 8 1 1 1 1
1 pile remaining: 52

pile/piles的单复数问题。

posted @ 2017-01-31 15:25  蟹脑板  阅读(191)  评论(0编辑  收藏  举报