欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

D. Stoned Game(博弈问题) Codeforces Round #666 (Div. 2)

程序员文章站 2022-03-15 23:36:56
...

原题链接: https://codeforces.com/contest/1397/problem/D

D. Stoned Game(博弈问题) Codeforces Round #666 (Div. 2)
测试样例:

input
2
1
2
2
1 1
output
T
HL

Note

In the first game, T removes a single stone from the only pile in his first turn. After that, although the pile still contains 1 stone, HL cannot choose from this pile because it has been chosen by T in the previous turn. Therefore, T is the winner.

题意: T和HL两个人玩游戏,游戏规则为:由若干个非空堆,玩家选择一个非空堆,然后从中取出单个石头。但是,一个人不能选择在前一回合中选择的筹码(另一位玩家选择的筹码,或者如果当前回合是第一回合,则玩家可以选择任何非空筹码)。 不能依次选择一堆的玩家输了,游戏结束了。T先开始,两个人都很聪明,都会选择最优策略。 问T和HL谁能赢?

解题思路: 如果我们是玩家,我们都很聪明,我们会怎么做?是不是先选择大的非空堆然后让另一个玩家去取走其他小的非空堆。总之我们都不希望自己的操作让非空堆变为1,所以我们都会先消耗大的非空堆去决策。 因为这个时候对手就可以选择此非空堆让你没有非空堆可以选择直至游戏结束。那么最优策略就是每个玩家都选取大的非空堆中的石头,那么直至选完之后对手无法选择则对手输掉比赛。 那么我们知道这个条件之后我们就可以去模拟这个比赛了,利用优先队列来实现,要注意模拟操作,具体看代码(贴了详细注释)。

AC代码:

/*
*邮箱:aaa@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>	//POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e2+3;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

int t,n;
priority_queue<int> q;//模拟,利用优先队列的自动排序操作便于实现。
int main(){
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	while(cin>>t){
        while(t--){
            cin>>n;
            int temp;
            rep(i,0,n-1){
                cin>>temp;
                q.push(temp);
            }
            int temp1,temp2;//temp1代表T所选取的非空堆,temp2代表HL选取的非空堆。
            while(1){
                //接下来我们去模拟游戏过程,注意游戏结束为对手没有非空堆可以选择。
                temp1=q.top();
                q.pop();
                if(q.empty()){
                    cout<<"T"<<endl;
                    break;
                }
                temp2=q.top();
                q.pop();
                //这里我们选择完之后将更新后的非空堆数量放回队列。
                if(temp1>1)q.push(temp1-1);//注意如果我们选择的非空堆数量为1的话,经过移除就为0了,故我们不用放回队列。
                if(temp2>1)q.push(temp2-1);
                //如果此时队列为空,说明T没有非空堆可以选择。
                if(q.empty()){
                    cout<<"HL"<<endl;
                    break;
                }
            }
        }
	}
	return 0;
}