[luogu7147] [THUPC2021 初赛]麻将模拟器 - 大模拟 - dp

传送门:https://www.luogu.com.cn/problem/P7147

写在前面

大家好我是泥萌可爱的出题人liuzhangfeiabc~

(别骂了我知道错了嘤嘤嘤)

说起来为什么会让我这个大一萌新来出这种题呢……喂这么毒瘤的题除了你还有谁会感兴趣

大家听我掩饰,哦不,解释,事情是这样的……最初他们组好题之后发现按往年惯例缺一道模拟,然后就找到了我

(为什么要找我啊?我也不想啊qwq)

为什么找你你自己心里还不清楚

总之接了这个活之后,按往年惯例一般大模拟会以一个游戏为背景(比如P5380 [THUPC2019]鸭棋),然后我就自然而然地想到去年整个机房被麻将支配的恐惧……

但是吧鉴于我的麻将水平也就那样,雀魂只有一个刚打上雀士1就弃了的号,也就勉强能分清日麻规则和国标规则的程度,于是造题的时候就很随心所欲(比如我题面里用的术语简直是乱七八糟大杂烩),到最后控制不住脑洞了又加了点特殊牌。当然最后出出来的结果是受到了出题组的一致好(tu)评(cao)(逃

行吧我们来看题解,当然作为大模拟我是不是只要写一个“本题按照题意模拟即可”就可以溜了……喂喂喂大家别走啊,喂!

接下来我们一个模块一个模块地看吧:

 

各种定义

#define gc getchar()
#define pc putchar
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
int pai[200],head = 1,fx = 1;
struct player{
	int a[20],sum;
	bool pass;
}p[4]; 

结构体player定义一名玩家,其中a数组表示他现有的牌,sum为手牌数,pass记录他有没有被pass。

pai表示牌堆,head表示牌堆顶,fx表示游戏进行的顺序。

 

输入输出处理

我的处理方法是把输入进来的每一张牌变成1~37的数字进行存储,输出的时候再还原成牌的名称。

输入处理就是一堆case:

int i,j,l;
string st;
for(i = 1;i <= 148;++i){
    cin>>st;
    if(st[0] >= '1' && st[0] <= '9'){
        l = st[0] - '0';
        switch(st[1]){
            case 'M' : pai[i] = l;break;
            case 'P' : pai[i] = l + 9;break;
            case 'S' : pai[i] = l + 18;break;
        }
    }
    else{
        switch(st[0]){
            case 'E' : pai[i] = 28;break;
            case 'S' : pai[i] = 29;break;
            case 'W' : pai[i] = 30;break;
            case 'N' : pai[i] = 31;break;
            case 'B' : pai[i] = 32;break;
            case 'F' : pai[i] = 33;break;
            case 'Z' : pai[i] = 34;break;
            case 'D' : pai[i] = 35;break;
            case 'R' : pai[i] = 36;break;
            case 'P' : pai[i] = 37;break;
        }
    }
}

输出的时候,先写了一个输出某特定编号牌的函数,也没有什么难度:

inline void outpai(int paii){//输出paii这一张牌
	if(paii <= 27) cout<<(paii - 1) % 9 + 1<<("MPS"[(paii - 1) / 9]);
	else if(paii <= 34) cout<<("ESWNBFZ"[paii - 28]);
	else if(paii == 35) cout<<"DOUBLE";
	else if(paii == 36) cout<<"REVERSE";
	else cout<<"PASS";
}

有了这个之后来实现题目要求的几种输出就比较自然了:

inline void draw(){//输出平局 
	cout<<"DRAW"<<endl;
	exit(0);
}
inline void win(int x){//输出x获胜 
	pc(x + 'A');pc(' ');cout<<"WIN"<<endl;
	exit(0);
} 
inline void hupai(int x){//输出x荣和 
	pc(x + 'A');cout<<" RON"<<endl;
	win(x);
}
inline void zimo(int x){//输出x自摸 
	pc(x + 'A');cout<<" SELFDRAWN"<<endl;
	win(x);
}
inline void in(int x,int paii){//输出x摸牌paii 
	pc(x + 'A');cout<<" IN ";
	outpai(paii);pc('\n');
}
inline void out(int x,int paii,int fg = -1){//输出x出牌paii,特判pass 
	pc(x + 'A');cout<<" OUT ";
	outpai(paii);
	if(fg >= 0) pc(' '),pc(fg + 'A');
	pc('\n');
}
inline void outchi(int x,int paii){//输出x吃,吃的第一张牌是paii 
	pc(x + 'A');cout<<" CHOW ";
	outpai(paii);pc(' ');outpai(paii + 1);pc(' ');outpai(paii + 2);pc('\n');
}
inline void outpeng(int x,int paii){//输出x碰paii 
	pc(x + 'A');cout<<" PONG ";
	outpai(paii);pc(' ');outpai(paii);pc(' ');outpai(paii);pc('\n');
}

 

进行回合、摸牌

int play(int x){//玩家x进行回合
	if(p[x].pass){
		p[x].pass = 0;
		return nxt(x);
	}
	mopai(x);
	return chupai(x);
}

这个框架很简单。一上来是判pass,这个nxt表示下家:

#define nxt(x) (((x) + fx + 4) % 4)

摸牌也相对简单:

inline void mopai(int x){//玩家x摸牌 
	if(head > 148) draw();
	p[x].a[++p[x].sum] = pai[head++];
	in(x,p[x].a[p[x].sum]);
	sort(p[x].a + 1,p[x].a + p[x].sum + 1);
}

摸完牌最好整理一下手牌。

注意别忘了开局要摸牌:

for(i = 1;i <= 13;++i){
    for(j = 0;j < 4;++j) mopai(j);//开局摸牌 
}

 

出牌

int chupai(int x){//出牌 
	if(p[x].a[p[x].sum] == 37){//pass 
		--p[x].sum;p[nxt(x)].pass = 1;
		out(x,37,nxt(x));
		return nxt(x);
	}
	if(p[x].a[p[x].sum] == 36){//reverse
		--p[x].sum;
		fx *= -1;
		out(x,36);
		return nxt(x);
	}
	if(p[x].a[p[x].sum] == 35){//double
		--p[x].sum;
		out(x,35);
		mopai(x);
		return chupai(x);
	}
	int chu = check(x);
	if(chu == -1) zimo(x);
	chup(x,chu);
	checkhu(x,chu);
	int px = checkpeng(chu);
	if(px >= 0) return chupai(px);
	if(checkchi(nxt(x),chu)) return chupai(nxt(x));
	return nxt(x);
}

先判断有没有特殊牌可出,有的话就出,没有就通过check函数确定下一张出什么/有没有自摸。

确定了出的牌是chu之后,用chup函数进行出牌。

再用checkhucheckpengcheckchi判断有无和牌、碰、吃。

注意吃碰之后不会摸牌,因此直接进入对应玩家的chupai函数而不是play函数。

chup函数不难实现:

inline void chup(int x,int chu){//玩家x出牌chu 
	int chid;
	for(chid = 1;chid <= p[x].sum;++chid) if(chu == p[x].a[chid]) break;
	swap(p[x].a[chid],p[x].a[p[x].sum]);
	--p[x].sum;
	sort(p[x].a + 1,p[x].a + p[x].sum + 1);
	out(x,chu);
}

出完牌也最好整理一下手牌。

接下来我们把重点放在其他几个函数上:

 

计算和牌距离和下一张出的牌

这可能是整道题里最难的部分,因为其余地方只需要无脑模拟就完事了,最多是写起来复杂一点。

但是这一块就需要有一些技巧。

如果你做过P5279 [ZJOI2019]麻将或者P5301 [GXOI/GZOI2019]宝牌一大堆的话,你应该能反应上来这需要一个dp:

dp[i][j][k][l][g]表示:目前考虑了前i种牌,已经凑齐了j个顺子和刻子、k个对子,计划凑成从第i-1种牌开始的顺子l个,从第i种牌开始的顺子g个,至少要往现在的手牌里添加多少张牌。

同时记录一个zy[i][j][k][l][g]表示在上述情况下,手里最后一张没有用上的手牌是什么。

转移:枚举i+1这种牌要用多少张(至少l+g张,至多4张)。假设要用x张,而手牌里有y张,需要讨论:

1、x<y:这说明手牌没用完,dp数组的值不会增加,zy数组的值变为i+1。

2、x=y:这说明手牌恰好用完,dp数组的值不会增加,zy数组的值不变。

3、x>y:这说明手牌不够,还差了x-y张是需要额外添加的,dp数组的值增加x-y,zy数组的值不变。

对于每个x,需要拿出l+g张用于之前未完成的顺子,剩余的部分可以用于开启新的顺子/凑一个对子/凑一个刻子,这样我们就可以通过讨论计算出下一步转移到的状态是什么。

这一部分的代码如下:

int sl[40],dp[40][5][2][3][3],zy[40][5][2][3][3];
#define zhuanyi(a,b,x,y) if((x) < (a) || ((x) == (a) && (y) > (b))) (a) = (x),(b) = (y)
pii work(int x){//计算和牌距离和下一张出的牌(最后一张没用的牌),x表示要凑出的顺子和刻子数目 
	memset(dp,0x3f,sizeof(dp));memset(zy,-1,sizeof(zy));
	dp[0][0][0][0][0] = 0;
	register int i,j,k,l,g,q,nx,ny,r;
	for(i = 0;i < 34;++i){
		for(j = 0;j <= x;++j){
			for(k = 0;k <= 1;++k){
				for(l = 0;l <= 2 && l + j <= x;++l){
					for(g = 0;g <= 2 && g + l + j <= x;++g) if(dp[i][j][k][l][g] < 15){
						for(q = l + g;q <= 4;++q){
							nx = dp[i][j][k][l][g] + max(0,q - sl[i + 1]);
							ny = (sl[i + 1] > q ? i + 1 : zy[i][j][k][l][g]);
							r = q - l - g;
							if(r >= 3 && j + l + 1 <= x) zhuanyi(dp[i + 1][j + l + 1][k][g][r - 3],zy[i + 1][j + l + 1][k][g][r - 3],nx,ny);
							if(r >= 2 && !k) zhuanyi(dp[i + 1][j + l][k + 1][g][r - 2],zy[i + 1][j + l][k + 1][g][r - 2],nx,ny);
							if(r <= 2) zhuanyi(dp[i + 1][j + l][k][g][r],zy[i + 1][j + l][k][g][r],nx,ny);
						}
						if(i % 9 == 0 || i >= 27) break; 
					}
					if(i % 9 == 0 || i >= 27) break; 
				}
			}
		}
	}
	return mp(dp[34][x][1][0][0],zy[34][x][1][0][0]);
}
int check(int x){//返回应该出哪一张牌,如果已经和了返回-1(因此也可以用于检验是否已经和牌) 
	memset(sl,0,sizeof(sl));
	for(int i = 1;i <= p[x].sum;++i) if(p[x].a[i] <= 34) ++sl[p[x].a[i]];
	pii as = work(4 - (14 - p[x].sum) / 3);
	return as.se;
}

其中check函数会对玩家x的手牌进行分类整理后扔给work函数。

 

和牌

inline bool ts(int x){//能和牌的前提是没有特殊牌 
	for(int i = 1;i <= p[x].sum;++i) if(p[x].a[i] > 34) return 1;
	return 0;
}
void checkhu(int x,int chu){//判断能否和牌 
	for(int i = nxt(x);i != x;i = nxt(i)) if(!ts(i)){
		p[i].a[++p[i].sum] = chu;
		if(check(i) == -1) hupai(i);
		--p[i].sum;
	}
}

这里在一开始写的时候遇到了一个bug:如果手牌里有特殊牌,work函数有可能在和牌距离不为0​的时候返回​-1,因此提前判了一下。

 

bool chkpeng(int x,int chu){//碰 
	memset(sl,0,sizeof(sl));
	for(int i = 1;i <= p[x].sum;++i) ++sl[p[x].a[i]];
	int lst = work(4 - (14 - p[x].sum) / 3).fi;
	if(sl[chu] >= 2){
		sl[chu] -= 2;
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outpeng(x,chu);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
	}
	return 0;
} 
int checkpeng(int chu){//对每一家判断能不能碰 
	for(int x = 0;x < 4;++x) if(chkpeng(x,chu)) return x;
	return -1;
}

所有玩家都能碰,所以要枚举不同的玩家,这里可以这么写是因为自己肯定不会碰自己刚出的牌。

具体实现就是先计算一下和牌距离,然后把手里相应的牌去掉再计算和牌距离,如果减小了就碰,碰完也最好整理一下手牌。

 

bool checkchi(int x,int chu){//吃 
	if(chu > 27) return 0;
	memset(sl,0,sizeof(sl));
	for(int i = 1;i <= p[x].sum;++i) ++sl[p[x].a[i]];
	int lst = work(4 - (14 - p[x].sum) / 3).fi;
	if(chu % 9 != 8 && chu % 9 != 0 && sl[chu + 1] && sl[chu + 2]){//x x+1 x+2 
		--sl[chu + 1];--sl[chu + 2];
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outchi(x,chu);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
		++sl[chu + 1];++sl[chu + 2];
	}
	if(chu % 9 != 1 && chu % 9 != 0 && sl[chu - 1] && sl[chu + 1]){//x-1 x x+1
		--sl[chu - 1];--sl[chu + 1];
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outchi(x,chu - 1);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
		++sl[chu - 1];++sl[chu + 1];
	}
	if(chu % 9 != 1 && chu % 9 != 2 && sl[chu - 2] && sl[chu - 1]){//x-2 x-1 x
		--sl[chu - 2];--sl[chu - 1];
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outchi(x,chu - 2);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
		++sl[chu - 2];++sl[chu - 1];
	}
	return 0;
}

吃与碰的区别在于只有下家能吃,但是有3种可能的吃法,都判断一下就好。其他细节跟碰类似。

 

大功告成!来看一下完整代码

#include<bits/stdc++.h>
#define gc getchar()
#define pc putchar
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
using namespace std;
int pai[200],head = 1,fx = 1;
struct player{
	int a[20],sum;
	bool pass;
}p[4]; 
inline void outpai(int paii){//输出paii这一张牌 
	if(paii <= 27) cout<<(paii - 1) % 9 + 1<<("MPS"[(paii - 1) / 9]);
	else if(paii <= 34) cout<<("ESWNBFZ"[paii - 28]);
	else if(paii == 35) cout<<"DOUBLE";
	else if(paii == 36) cout<<"REVERSE";
	else cout<<"PASS";
}
inline void draw(){//输出平局 
	cout<<"DRAW"<<endl;
	exit(0);
}
inline void win(int x){//输出x获胜 
	pc(x + 'A');pc(' ');cout<<"WIN"<<endl;
	exit(0);
} 
inline void hupai(int x){//输出x荣和 
	pc(x + 'A');cout<<" RON"<<endl;
	win(x);
}
inline void zimo(int x){//输出x自摸 
	pc(x + 'A');cout<<" SELFDRAWN"<<endl;
	win(x);
}
inline void in(int x,int paii){//输出x摸牌paii 
	pc(x + 'A');cout<<" IN ";
	outpai(paii);pc('\n');
}
inline void out(int x,int paii,int fg = -1){//输出x出牌paii,特判pass 
	pc(x + 'A');cout<<" OUT ";
	outpai(paii);
	if(fg >= 0) pc(' '),pc(fg + 'A');
	pc('\n');
}
inline void outchi(int x,int paii){//输出x吃,吃的第一张牌是paii 
	pc(x + 'A');cout<<" CHOW ";
	outpai(paii);pc(' ');outpai(paii + 1);pc(' ');outpai(paii + 2);pc('\n');
}
inline void outpeng(int x,int paii){//输出x碰paii 
	pc(x + 'A');cout<<" PONG ";
	outpai(paii);pc(' ');outpai(paii);pc(' ');outpai(paii);pc('\n');
}
inline void mopai(int x){//玩家x摸牌 
	if(head > 148) draw();
	p[x].a[++p[x].sum] = pai[head++];
	in(x,p[x].a[p[x].sum]);
	sort(p[x].a + 1,p[x].a + p[x].sum + 1);
}
inline void chup(int x,int chu){//玩家x出牌chu 
	int chid;
	for(chid = 1;chid <= p[x].sum;++chid) if(chu == p[x].a[chid]) break;
	swap(p[x].a[chid],p[x].a[p[x].sum]);
	--p[x].sum;
	sort(p[x].a + 1,p[x].a + p[x].sum + 1);
	out(x,chu);
}
int sl[40],dp[40][5][2][3][3],zy[40][5][2][3][3];
#define zhuanyi(a,b,x,y) if((x) < (a) || ((x) == (a) && (y) > (b))) (a) = (x),(b) = (y)
pii work(int x){//计算和牌距离和下一张出的牌(最后一张没用的牌),x表示要凑出的顺子和刻子数目 
	memset(dp,0x3f,sizeof(dp));memset(zy,-1,sizeof(zy));
	dp[0][0][0][0][0] = 0;
	register int i,j,k,l,g,q,nx,ny,r;
	for(i = 0;i < 34;++i){
		for(j = 0;j <= x;++j){
			for(k = 0;k <= 1;++k){
				for(l = 0;l <= 2 && l + j <= x;++l){
					for(g = 0;g <= 2 && g + l + j <= x;++g) if(dp[i][j][k][l][g] < 15){
						for(q = l + g;q <= 4;++q){
							nx = dp[i][j][k][l][g] + max(0,q - sl[i + 1]);
							ny = (sl[i + 1] > q ? i + 1 : zy[i][j][k][l][g]);
							r = q - l - g;
							if(r >= 3 && j + l + 1 <= x) zhuanyi(dp[i + 1][j + l + 1][k][g][r - 3],zy[i + 1][j + l + 1][k][g][r - 3],nx,ny);
							if(r >= 2 && !k) zhuanyi(dp[i + 1][j + l][k + 1][g][r - 2],zy[i + 1][j + l][k + 1][g][r - 2],nx,ny);
							if(r <= 2) zhuanyi(dp[i + 1][j + l][k][g][r],zy[i + 1][j + l][k][g][r],nx,ny);
						}
						if(i % 9 == 0 || i >= 27) break; 
					}
					if(i % 9 == 0 || i >= 27) break; 
				}
			}
		}
	}
	return mp(dp[34][x][1][0][0],zy[34][x][1][0][0]);
}
int check(int x){//返回应该出哪一张牌,如果已经和了返回-1(因此也可以用于检验是否已经和牌) 
	memset(sl,0,sizeof(sl));
	for(int i = 1;i <= p[x].sum;++i) if(p[x].a[i] <= 34) ++sl[p[x].a[i]];
	pii as = work(4 - (14 - p[x].sum) / 3);
	return as.se;
}
inline bool ts(int x){//能和牌的前提是没有特殊牌 
	for(int i = 1;i <= p[x].sum;++i) if(p[x].a[i] > 34) return 1;
	return 0;
}
#define nxt(x) (((x) + fx + 4) % 4)
void checkhu(int x,int chu){//判断能否和牌 
	for(int i = nxt(x);i != x;i = nxt(i)) if(!ts(i)){
		p[i].a[++p[i].sum] = chu;
		if(check(i) == -1) hupai(i);
		--p[i].sum;
	}
}
bool chkpeng(int x,int chu){//碰 
	memset(sl,0,sizeof(sl));
	for(int i = 1;i <= p[x].sum;++i) ++sl[p[x].a[i]];
	int lst = work(4 - (14 - p[x].sum) / 3).fi;
	if(sl[chu] >= 2){
		sl[chu] -= 2;
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outpeng(x,chu);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
	}
	return 0;
} 
int checkpeng(int chu){//对每一家判断能不能碰 
	for(int x = 0;x < 4;++x) if(chkpeng(x,chu)) return x;
	return -1;
}
bool checkchi(int x,int chu){//吃 
	if(chu > 27) return 0;
	memset(sl,0,sizeof(sl));
	for(int i = 1;i <= p[x].sum;++i) ++sl[p[x].a[i]];
	int lst = work(4 - (14 - p[x].sum) / 3).fi;
	if(chu % 9 != 8 && chu % 9 != 0 && sl[chu + 1] && sl[chu + 2]){//x x+1 x+2 
		--sl[chu + 1];--sl[chu + 2];
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outchi(x,chu);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
		++sl[chu + 1];++sl[chu + 2];
	}
	if(chu % 9 != 1 && chu % 9 != 0 && sl[chu - 1] && sl[chu + 1]){//x-1 x x+1
		--sl[chu - 1];--sl[chu + 1];
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outchi(x,chu - 1);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
		++sl[chu - 1];++sl[chu + 1];
	}
	if(chu % 9 != 1 && chu % 9 != 2 && sl[chu - 2] && sl[chu - 1]){//x-2 x-1 x
		--sl[chu - 2];--sl[chu - 1];
		if(lst > work(3 - (14 - p[x].sum) / 3).fi){
			outchi(x,chu - 2);
			p[x].sum = 0;
			for(int i = 1;i <= 37;++i){
				while(sl[i]) p[x].a[++p[x].sum] = i,--sl[i];
			}
			return 1;
		}
		++sl[chu - 2];++sl[chu - 1];
	}
	return 0;
}
int chupai(int x){//出牌 
	if(p[x].a[p[x].sum] == 37){//pass 
		--p[x].sum;p[nxt(x)].pass = 1;
		out(x,37,nxt(x));
		return nxt(x);
	}
	if(p[x].a[p[x].sum] == 36){//reverse
		--p[x].sum;
		fx *= -1;
		out(x,36);
		return nxt(x);
	}
	if(p[x].a[p[x].sum] == 35){//double
		--p[x].sum;
		out(x,35);
		mopai(x);
		return chupai(x);
	}
	int chu = check(x);
	if(chu == -1) zimo(x);
	chup(x,chu);
	checkhu(x,chu);
	int px = checkpeng(chu);
	if(px >= 0) return chupai(px);
	if(checkchi(nxt(x),chu)) return chupai(nxt(x));
	return nxt(x);
}
int play(int x){//玩家x进行回合
	if(p[x].pass){
		p[x].pass = 0;
		return nxt(x);
	}
	mopai(x);
	return chupai(x);
}
int main(){
	int i,j,l;
	string st;
	for(i = 1;i <= 148;++i){
		cin>>st;
		if(st[0] >= '1' && st[0] <= '9'){
			l = st[0] - '0';
			switch(st[1]){
				case 'M' : pai[i] = l;break;
				case 'P' : pai[i] = l + 9;break;
				case 'S' : pai[i] = l + 18;break;
			}
		}
		else{
			switch(st[0]){
				case 'E' : pai[i] = 28;break;
				case 'S' : pai[i] = 29;break;
				case 'W' : pai[i] = 30;break;
				case 'N' : pai[i] = 31;break;
				case 'B' : pai[i] = 32;break;
				case 'F' : pai[i] = 33;break;
				case 'Z' : pai[i] = 34;break;
				case 'D' : pai[i] = 35;break;
				case 'R' : pai[i] = 36;break;
				case 'P' : pai[i] = 37;break;
			}
		}
	}
	for(i = 1;i <= 13;++i){
		for(j = 0;j < 4;++j) mopai(j);//开局摸牌 
	}
	int nw = 0;
	while(1) nw = play(nw);
	return 0;
}

 

后记

泥萌怎么能说我这题比猪国杀还毒瘤呢qwq

这题std明明只写了3个小时,代码只有6个k,验题人甚至只写了4个k

再说了场上可是有足足两车人过了这题啊qaq

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值