Week(6) 限时大模拟

A-掌握魔法の东东Ⅱ

题目描述

从瑞神家打牌回来后,东东痛定思痛,决定苦练牌技,终成赌神!
东东有 A × B 张扑克牌。每张扑克牌有一个大小(整数,记为a,范围区间是 0 到 A - 1)和一个花色(整数,记为b,范围区间是 0 到 B - 1)。
扑克牌是互异的,也就是独一无二的,也就是说没有两张牌大小和花色都相同。
“一手牌”的意思是你手里有5张不同的牌,这 5 张牌没有谁在前谁在后的顺序之分,它们可以形成一个牌型。 我们定义了 9 种牌型,如下是 9 种牌型的规则,我们用“低序号优先”来匹配牌型,即这“一手牌”从上到下满足的第一个牌型规则就是它的“牌型编号”(一个整数,属于1到9):

1.同花顺: 同时满足规则 2 和规则 3.
2.顺子 : 5张牌的大小形如 x, x + 1, x + 2, x + 3, x + 4
3.同花 : 5张牌都是相同花色的.
4.炸弹 : 5张牌其中有4张牌的大小相等.
5.三带二 : 5张牌其中有3张牌的大小相等,且另外2张牌的大小也相等.
6.两对: 5张牌其中有2张牌的大小相等,且另外3张牌中2张牌的大小相等.
7.三条: 5张牌其中有3张牌的大小相等.
8.一对: 5张牌其中有2张牌的大小相等.
9.要不起: 这手牌不满足上述的牌型中任意一个.

现在, 东东从A × B 张扑克牌中拿走了 2 张牌!分别是 (a1, b1) 和 (a2, b2). (其中a表示大小,b表示花色)
现在要从剩下的扑克牌中再随机拿出 3 张!组成一手牌!!
其实东东除了会打代码,他业余还是一个魔法师,现在他要预言他的未来的可能性,即他将拿到的“一手牌”的可能性,我们用一个“牌型编号(一个整数,属于1到9)”来表示这手牌的牌型,那么他的未来有 9 种可能,但每种可能的方案数不一样。
现在,东东的阿戈摩托之眼没了,你需要帮他算一算 9 种牌型中,每种牌型的方案数。

Input

第 1 行包含了整数 A 和 B (5 ≤ A ≤ 25, 1 ≤ B ≤ 4).

第 2 行包含了整数 a1, b1, a2, b2 (0 ≤ a1, a2 ≤ A - 1, 0 ≤ b1, b2 ≤ B - 1, (a1, b1) ≠ (a2, b2)).

Output

输出一行,这行有 9 个整数,每个整数代表了 9 种牌型的方案数(按牌型编号从小到大的顺序)

Examples

Input
5 2
1 0 3 1

Output
0 8 0 0 0 12 0 36 0

Input
25 4
0 0 24 3

Output
0 0 0 2 18 1656 644 36432 113344

解题思路

解答这道题我们必须要遍历所有“一手牌”的可能性,在此基础上再去以低序号优先判断每手牌的“牌型”,判断牌型不难写,用一串“if…else…”即可解决,现在我们要考虑用什么方式去遍历所有的“一手牌”。结合最近所学的内容,我们很容易想到用dfs去枚举所有可能的牌型。
已知有两张牌,我们还需要枚举三张其他的牌,而一张牌有两个性质——大小、花色,因此我们要确定对不同性质的枚举次序。这里我先枚举大小,在大小相同的基础上枚举不同的花色。从第一张牌(0,0)开始枚举,那么第二张牌就枚举到(0,1),那么先将这两张牌确定,再依次向后枚举第三张牌(0,2)、(0,3)…(0,B-1)、(1,0)…直到(A-1,B-1),至此在前两张牌确定了基础上,第三张牌的所有情况枚举完毕,我们开始回溯对第二张牌的枚举(0,2),现在又重复对第三张牌的枚举。当第二张牌枚举到(A-1,B-1),我们就开始回溯对第一张牌枚举(0,1),按此规律依次枚举下去即可。

注意

1、枚举过程中枚举到(a1,b1)、(a2,b2)直接回溯;
2、枚举当一张牌的花色为B-1时,下一张牌直接从(a+1,0)开始枚举,否则就枚举(a,b+1)。

if(b<B-1) {
		for(int j=b+1;j<B;++j)
			dfs(a,j,n+1); 
	}
for(int i=a+1;i<A;++i) {  
		for(int j=0;j<B;++j){
			dfs(i,j,n+1);
	}

3、一定要注意将存牌数组和判断数组区分开,因为每次判断前都要将这一手牌排序,排序之后已有的牌序被打乱,已枚举的前两张牌在存牌数组中的位置发生改变,而我们对第三张的枚举是建立在前两张牌已确定的基础上的,所以sort前应该将已枚举好的牌复制到新的判断数组中,对新的判断数组的进行排序不会影响已枚举好的前两张牌!

P poker[5];//判断数组
P pp[5];//存牌数组

for(int i=0;i<5;++i) {
			poker[i].num=pp[i].num;
			poker[i].col=pp[i].col;
		}
sort(poker,poker+5);

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm> 

using namespace std;

struct P{
	int num,col;
	bool operator<(const P &p) const {
		return num<p.num;
	}
};

P poker[5];//判断数组
P pp[5];//存牌数组
int A,B;
int a1,b1,a2,b2;

int ccc[10]={0};//存储每种牌型编号的方案数

void dfs(int a,int b,int n) {
	if((a==a1&&b==b1)||(a==a2&&b==b2)) return;//直接回溯
	pp[n+1].num=a,pp[n+1].col=b;
	if(n==3) {
		for(int i=0;i<5;++i) {
			poker[i].num=pp[i].num;
			poker[i].col=pp[i].col;
		}
		sort(poker,poker+5);
		if((poker[0].col==poker[1].col)&&(poker[1].col==poker[2].col)&&(poker[2].col==poker[3].col)&&(poker[3].col==poker[4].col)) {
			if((poker[0].num+1==poker[1].num)&&(poker[1].num+1==poker[2].num)&&(poker[2].num+1==poker[3].num)&&(poker[3].num+1==poker[4].num))
				ccc[1]++;
			else ccc[3]++;
		}else if(poker[0].num+1==poker[1].num&&poker[1].num+1==poker[2].num&&poker[2].num+1==poker[3].num&&poker[3].num+1==poker[4].num) {
			ccc[2]++;
		}else if((poker[0].num==poker[1].num&&poker[1].num==poker[2].num&&poker[2].num==poker[3].num)||
		         (poker[1].num==poker[2].num&&poker[2].num==poker[3].num&&poker[3].num==poker[4].num)) {
		    ccc[4]++;	
		}else if((poker[0].num==poker[1].num&&poker[1].num==poker[2].num&&poker[3].num==poker[4].num)||
				 (poker[0].num==poker[1].num&&poker[2].num==poker[3].num&&poker[3].num==poker[4].num)) {
			ccc[5]++; 	
		}else if((poker[0].num==poker[1].num&&poker[2].num==poker[3].num)||(poker[0].num==poker[1].num&&poker[3].num==poker[4].num)
				||(poker[1].num==poker[2].num&&poker[3].num==poker[4].num)) {
			ccc[6]++;
		}else if((poker[0].num==poker[1].num&&poker[1].num==poker[2].num)||(poker[2].num==poker[3].num&&poker[3].num==poker[4].num)
				||(poker[1].num==poker[2].num&&poker[2].num==poker[3].num)) {
			ccc[7]++;
		}else if(poker[0].num==poker[1].num||poker[1].num==poker[2].num||poker[2].num==poker[3].num||poker[3].num==poker[4].num) {
			ccc[8]++;
		}else ccc[9]++;
		
		return ;		
	}
	if(b<B-1) {
		for(int j=b+1;j<B;++j)
			dfs(a,j,n+1); 
	}
	for(int i=a+1;i<A;++i) {  
		for(int j=0;j<B;++j){
			dfs(i,j,n+1);
		}
	}
}

int main() {
	scanf("%d %d",&A,&B);
	scanf("%d %d %d %d",&a1,&b1,&a2,&b2);
	pp[0].num=a1;pp[0].col=b1;pp[1].num=a2;pp[1].col=b2;
	for(int i=0;i<A;++i) {
		for(int j=0;j<B;++j)
		dfs(i,j,1);
	}
	for(int i=1;i<=9;++i)
		printf("%d ",ccc[i]);
	printf("\n");
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值