2021EC-final博弈论E题Prof. Pang and Poker

题目链接:Problem - E - Codeforces

题目意思:有三个人玩游戏,Alice,Bob,还有Prof. Pang。Alice和Bob分别有n,m张扑克,Pang只有一张,出牌顺序是Alice,Bob,Pang,Alice。类似斗地主一样的规则,但是不同的是,每次只能出一张牌。Alice想要Pang出完手里的牌(送牌让他走),Bob想要阻止。当且仅当Pang出完手里的唯一的牌,他会开心。

我们可以得知题目的规则类似斗地主,假设我们是Alice,那么我们就要想办法送牌给Pang,让Pang走完手中的牌,又或者通过一些手段,让Bob出牌,送给Pang。

对于博弈论的题,我们可以先分析,哪些情况是必胜的(这里我定义Alice必定能让Pang出完手里的牌是必胜的)。遇到这样的题目,我们不能一上来就凭感觉狂写一通,不能想到什么就写什么,因为这样很容易漏掉条件,我们最好按照某种特定的条件,不断分类,让自己所分类的条件,可以涵盖所有的可能情况。

首先,如果你是Alice,你想要Pang走完自己的牌。我们可以先看两个大前提的条件。

那么如果Alice的牌数n = 1,必输。因为Alice先手,走完这张牌,游戏就结束了

如果Alice所有的牌,都 >= Pang的牌,必输。因为你出的牌,Pang根本要不起,那么Bob就可以一直不接你的牌,直到你把自己的牌走完,游戏结束。

除此之外有一点很好发现的特点,那就是,带入Bob,如果Bob手里小于Pang的牌很多,那么Bob就没办法走完全部的牌,如果平时玩过斗地主,这个特点非常容易发现。

那么,我们就可以对Bob手里小于Pang的牌的数量进行分类。我们假设,Bob手里小于Pang的牌的个数为x。那么:

若x>=2,Bob必输。

因为,在除去之前的两个Alice必败条件,Alice至少有两张牌,而且至少一张小于Pang的牌。那么Alice只需要开局打出小于Pang的那张牌。如果Bob不压我们,Pang就会打出自己的牌,我们赢。所以Bob必须要压我们,但如果他压了我们,我们可以选择不出牌,后面无论Bob出什么,我们都不要,让Bob一直出牌,直到Bob打出了一张小于pang的牌,我们胜利。所以综上,无论怎么样,如果Bob手里小于pang的牌至少有两张,那么我们必赢,bob必输。

若x=0,Bob必胜。

如果Bob手里的牌,都是大于等于pang的,那么我们出牌,只要是小于pang的牌,Bob就选择压我们,一直出,就一直压。到最后,要么Bob打完了手里所有的牌,要么Alice打完了所有能送pang赢的牌,所以,无论如何,都是Bob赢。

接下来,就剩最后一个大类了,也是最容易出错的一类。

当x=1的时候。

首先,我们先判断一个特殊情况:

如果Bob只有一张牌,且Alice的那张小牌 >= Bob手中的牌,Bob必输,否则Bob必胜。因为Alice只要出那张牌,Bob的牌出不了,也就是Bob不能跑完全部的牌,也就只能眼睁睁看着Alice的那张牌送到pang的手里,然后pang出牌,游戏结束。但如果Alice手里小于pang的那种牌,比Bob的手里的牌还小,那么Bob还是赢的,因为只要Alice出了那张牌,Bob会赶在pang能出牌之前,把自己手里唯一的牌打出去,游戏结束。

此后,我们再判断Alice手中的牌

若Alice < pang 的牌的数量 = 1,Bob必胜

因为只要Alice出手了这唯一一张能让pang赢的牌,那么Bob就可以压制Alice的那张牌,灭了他唯一的希望,此后,Bob就可以随意出,只要把小于pang的牌留到最后一手,然后走掉,结束游戏。那如果Alice选择接手,但这时候Alice手里的牌都是大于等于pang的,那么Alice又回到了最开始我们说的必输的局面。所以这种情况下,Bob怎么样都是赢的。

若Alice < pang 的牌的数量 >= 2:

如果Alice最大的牌 > Bob最大的牌,并且Alice存在一张牌 < pang 并且 >= Bob手中的小牌,同时Alice的牌还要多余3张,Bob必输 ,否则Bob必胜。因为Alice只要出一张最小的牌,Bob必须阻拦 ,之后Alice一直不接牌,让Bob一直出牌,直到Bob剩下出完倒数第二张牌,也就是最后一个 > pang的牌,这时候Alice再出手,压住Bob,然后再出一张Bob要不起,但是pang要得起的小牌,让pang赢。之所以Alice的牌要 > 3张,是因为除去开局出的小牌,手里最大的牌,以及之后送给pang的牌,还要有多余的牌在手里,不然的话,打出送给pang的牌,自己手里没牌,游戏就结束了(这点很容易错)

最后附上AC代码

#include
#define ll int
#define LL long long
#define L(i,j,k) for(ll i=j;i<=k;++i)
#define R(i,j,k) for(ll i=j;i>=k;--i)
using namespace std;
const ll N=5e3+10,mod=1e9+7;

ll n,m,k,p,t,x,y,z,c;
LL ans;
ll a[60],b[60];
char sa[60][5],sb[60][5],sc[5];

ll cal(char ch){
	if(ch=='A')return 14;
	else if(ch=='K')return 13;
	else if(ch=='Q')return 12;
	else if(ch=='J')return 11;
	else if(ch=='T')return 10;
	else return (ch-'0');
}

void solve(){
	scanf("%d%d",&n,&m);
	L(i,1,n)scanf("%s",sa[i]),a[i]=cal(sa[i][0]);
	L(i,1,m)scanf("%s",sb[i]),b[i]=cal(sb[i][0]);
	sort(a+1,a+n+1);sort(b+1,b+m+1);
	scanf("%s",sc);c=cal(sc[0]);
	int am,bm,amax,bmax;
	am=bm=amax=bmax=0;
	int a_maxmin=0;
	int ada=0;
	for(int i=1;i<=m;i++)   //求出bob小于c的个数
	{
		if(b[i]=c)
		{
			ada++;
		}
		else
		{
			if(a[i]>a_maxmin)	//最大的小于C的数字
			{
				a_maxmin=a[i];
			}
		}
	}
	int flag=1;
	if(n==1||ada==n)
	{
		printf("Shou\n");
		return ;
	}
	if(bm>=2)
	{
		printf("Pang\n");
		return;
	}
	else if(bm==0)
	{
		printf("Shou\n");
		return ;
	}
	else
	{
	    if(m==1)	//B大为0 也就是没有大于等于c的牌
        {
            if(a_maxmin>=b[1])    ///存在大于等于m且 小于C
            {
                printf("Pang\n");
                return ;
            }
            else
            {
                printf("Shou\n");
                return ;
            }
        }
		if((n-ada)==1)    //a小为1
		{
            printf("Shou\n"); return ;
		}
		else         ///A小大于等于2个
		{
			if(b[m]>=a[n])	//有牌权
			{
				printf("Shou\n");
				return ;
			}
			else
			{
				if(a_maxmin>=b[1]&&n>3)
				{
					printf("Pang\n");
				}
				else
				{
					printf("Shou\n");
				}
			}
		}
	}
}

int main(){
	ll cas=1;
	scanf("%d",&cas);
	while(cas--)solve();
}

你可能感兴趣的:(博弈论,算法)