20.选举

目录

题目

思路

具体步骤

C++完整代码(含详细注释)


题目

在遥远的相簿国有两个种族,分别是冬马族和雪菜族,每个人都属于这两个种族之一。如今,又到了选举元首的时候了,所有 n 个人排成一排等待投票。

    相簿国的选举制度比较奇特,并不是看谁的票数多,而是使用一票否决制度,并且所有人都可以投一张票或者不投票。如果排在前面的人把排在后面的人一票否决了,那么后面的人不能参与竞选,也不能投出他的那一票了。而如果排在后面的人把排在前面的人一票否决了,那么排在前面的人不能参与竞选,但是已经投出的那一票仍然有效。如果一轮投完仍然有不只一个竞选者,那么这些留下的人再投一轮,还没有停止就再投一轮……直到剩下一人为止,但投票的先后顺序不变。

为了保证每轮投票中都有更多人可以投票,规定竞选者优先给在他投票时已经投过票的异族人,每轮投票结束时重置竞选人的投票状态

    所有人都希望自己族的人能当选元首(而不是希望自己当元首),并且会为此采取最优策略。现在给出排队中每个人的种族,请问最后是哪个种族的人会当选元首?

输入

输入第一行一个数 n ,表示相簿国里的人数。

第二行一个长度为 n 的字符串 s ,从前到后依次表示排队投票的人所属的种族。D 表示冬马族,而 X 表示雪菜族。

输出

输出一个字符 D 或 X ,表示是哪一族的人当选。

注意

数据保证1<=n <=200000。

测试用例

用例1.

输入:

5↵

DDXXX↵

输出:

D↵

用例2.

输入:

6↵

DDXXXX↵

输出:

X↵


思路

我们首先需要明确每一个族人有两种权利:投票权竞选权

因此,

我们可以用D和X分别记录有投票权的族人;

使用栈(stack)来存放仍有竞选权的族人。

值得注意的是,

前面的一个人能够让后面的异族人同时丧失投票权和竞选权,

因为“如果排在前面的人把排在后面的人一票否决了,那么后面的人不能参与竞选,也不能投出他的那一票了”;

而要让前面的一个人丧失投票权和竞选权则需要后面的两个异族人,

因为“如果排在后面的人把排在前面的人一票否决了,那么排在前面的人不能参与竞选,但是已经投出的那一票仍然有效

简单来说,是因为需要一个异族人去花掉前面的人的投票权,另一个异族人使用竞选权让前面的人丧失竞选权。


具体步骤

代码首先输入选票的数量和选票字符串。然后遍历字符串,检查当前选票是“D”还是“X”。根据当前选票和栈中现有的竞选人,确定具有当前选票的候选人是否有权竞选或需要被淘汰。

如果当前选票是“D”且没有具有投票权的“X”候选人,则将“D”候选人加入栈中,并增加“D”票数。如果栈中有“X”候选人,则“D”候选人可以淘汰栈中的所有“X”候选人,并将自己加入栈中。

如果当前选票是“X”且没有具有投票权的“D”候选人,则将“X”候选人加入栈中,并增加“X”票数。如果栈中有“D”候选人,则“X”候选人可以淘汰栈中的所有“D”候选人,并将自己加入栈中。

在遍历完所有选票后,代码计算栈中剩余的候选人数量。栈中候选人数量较多的种族被宣布为获胜者。如果剩余候选人数量对于两个种族来说是相同的,则根据栈中最后一个候选人确定获胜者。


C++完整代码(含详细注释)

#include <iostream>
#include <stack>
using namespace std;

int main() {
    int n;
    string s;
    stack<char> st;//栈用于存放还有竞选权的人
    int D = 0, X = 0;//记录两个种族的投票权
    cin >> n;
    cin >> s;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == 'D') {//遍历到D时
            if (X == 0) {//如果X的投票权为0,则说明D有竞选权和投票权
                if (st.empty()) {//栈为空
                    st.push('D');
                    D++;
                }
                else {//栈不为空
                    if (st.top() == 'D') {//栈顶为D
                        st.push('D');
                        D++;
                    }
                    else {//栈顶为X,则需要D使用投票权将前面的X淘汰,但自己仍有竞选权
                        st.pop();//将前面的X淘汰
                        int num = 1;//记录X的淘汰人数和D的竞选人数
                        while (i<n-1&&s[i + 1] == 'D' &&!st.empty() && st.top() == 'X') {
                            //在字符串下个仍为D且栈顶仍为X时的,可以连续将X一次性连续淘汰
                            i++;
                            st.pop();
                            num++;
                        }
                        while (num--) {//将有竞选权的D入栈
                            st.push('D');
                        }
                    }
                }
            }
            else {//如果X的投票权不为0,则X使用投票权让D淘汰
                X--;
            }
          }
        
        else if (s[i] == 'X') {//遍历到X时
            if (D == 0) {//如果D的投票权为0,则说明D有竞选权和投票权
                if (st.empty()) {//栈为空
                    st.push('X');
                    X++;
                }

                else {//栈不为空
                    if (st.top() == 'X') {//栈顶为X
                        st.push('X');
                        X++;
                    }
                    else {//栈顶为D,则需要X使用投票权将前面的X淘汰,但自己仍有竞选权
                        st.pop();
                        int num = 1;//记录D的淘汰人数和X的竞选人数
                        while (i < s.size() - 1 && s[i + 1] == 'X' && !st.empty() && st.top() == 'D') {
                            //  //在字符串下个仍为X且栈顶仍为D时的,可以连续将D一次性连续淘汰
                            i++;
                            st.pop();
                            num++;
                        }
                        while (num--) {//将有竞选权的X入栈
                            st.push('X');
                        }
                    }
                }
            }
            else {//如果D的投票投票权不为0
                D--;
            }
           }
        }
    

    int D1 = 0, X1 = 0;//用于记录竞选者
    char last;

    while (!st.empty()) {//计算剩余竞选者
        if (st.size() == 1) last = st.top();
        if (st.top() == 'D') D1++;
        else X1++;
        st.pop();
    }
    //哪个种族剩余的竞选者多,哪个种族就会赢得竞选
    if (D1 > X1) cout << 'D' << endl;
    else if (X1 > D1) cout << 'X' << endl;
    else cout << last << endl;//竞选者人数相同,则在前面(即栈顶)的种族会赢,因为前面的可以让后面的失去投票权

    return 0;
}


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

榆榆欸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值