题目链接: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();
}