hdu计算机学院大学生程序设计竞赛(2015’11)1003 玩骰子

玩骰子


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1017    Accepted Submission(s): 306




Problem Description
  Nias与Ains都特别喜欢玩骰子,而且都自以为比对方玩得更溜。
  终于有一天,他们决定用骰子来一决高下!
  一般的骰子玩法已经不足以体现他们的水平了,于是他们自创了一套玩法来PK:
首先,每人掷3个骰子;之后,可以选择其中一个骰子重新掷(当然也可以放弃这一步),最后,比较投掷结果的大小,结果大的那方获胜,一样的话为平局。
  大小比较规则为:
  三个一样数字的骰子称为三条;两个一样数字的骰子称为对子;只有一个数字的骰子成为散牌。三条>对子>散牌。当双方结果都为三条时,直接比较三条数字的大小;都有对子时,先比较对子数字的大小,若相同,再比较剩下的骰子的数字的大小;都只有散牌时,先比较最大的数字的大小,若相同,再比较次大的数字的大小,还相同,最后比较最小的数字的大小。


  现在Nias已经投了3个骰子,还剩一次机会可以选择其中一个骰子重新投(或不选),而且他已经知道了Ains的最后投掷结果,求Nias获胜的概率有多大。
 


Input
输入数据第一行为一个整数T,表示有T组测试数据。
接下来T行,每行6个1~6的整数,前三个表示Nias第一次的投掷结果,后三个表示Aias最终的投掷结果。
 


Output
请输出Nias获胜的概率,结果保留3位小数,每组输出占一行。
 


Sample Input
4
2 3 5 3 3 4
3 3 1 2 2 2
6 2 1 5 4 3
1 2 3 4 4 1
 


Sample Output
0.333
0.167
1.000
0.000

刚开始理解错了,以为是从3个骰子中任取一个然后掷骰子,第一个数据怎么算怎么不对,后来才知道是选定获胜几率最大的,然后掷骰子,求最大的概率,也就是选获胜可能性最大的骰子,掷之,算出其获胜概率。

对Nias的第一个骰子进行从1到6枚举,然后用一个check函数来判断是否获胜,若获胜cou++,最后cou / 6求出Nias掷这个骰子的获胜概率,同样求出第二个,第三个的获胜概率,取最大值作为结果即可。


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <algorithm>
#include<functional>
#include <set>

using namespace std;

int nias[3], ains[3];
int size = sizeof(nias);

bool check(const int *n, const int *a) {
	int nt[3], at[3];   //因为也要保持t1的只读性否则枚举每个骰子的时候会出错
	memcpy(nt, n, size);
	memcpy(at, a, size);
	int cou1, cou2;

	set<int> s1, s2;  //用set来筛,看3个骰子中有几种骰子
	for (int i = 0; i < 3; i++) {
		s1.insert(nt[i]);
		s2.insert(at[i]);
	}
	cou1 = s1.size();
	cou2 = s2.size();

	if (cou1 < cou2) {  //此时nias和ains中骰子种数分别为:(2,3)或(1,3)或(1,2)nias胜
		return true;
	}
	else if (cou1 == cou2) {   //相等的时候分类讨论都只有1或2或3种时的情况
		if (cou1 == 1) {
			if (nt[0] > at[0])  //直接判断其中任意元素大小
				return true;
			else return false;
		}
		else if (cou1 == 2) {
			sort(nt, nt + 3); //先排序,排序后肯定0号或者2号元素有且只有一个和1号元素相同的
			sort(at, at + 3);
			int tem;
			if (nt[1] == nt[2]) {  //将相同的元素靠前放
				tem = nt[2];
				nt[2] = nt[0];
				nt[0] = tem;
			}
			if (at[1] == at[2]) {
				tem = at[2];
				at[2] = at[0];
				at[0] = tem;
			}
			if (nt[0] < at[0]) {   //先比较相同元素即“对子”大小
				return false;
			}
			else if (nt[0] > at[0]) {   //若相同再比较剩下的成单的
				return true;
			}
			else {
				if (nt[2] > at[2])
					return true;
				else return false;  //注意平局时不算赢
			}
		}
		else if (cou1 == 3) {
			sort(nt, nt + 3, greater<int>());   //降序排列,挨个比较
			sort(at, at + 3, greater<int>());
			for (int i = 0; i < 3; i++) {
				if (nt[i] > at[i])
					return true;
				else if (nt[i] < at[i])
					return false;
			}
			return false;  //平局
		}
	}
	else if (cou1 > cou2) {  //此时nias和ains中骰子种数分别为:(3,2)或(3,1)或(2,1)nias负
		return false;
	}
}

double MAX(double a, double b) {
	if (a > b) {
		return a;
	}
	else {
		return b;
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--) {
		for (int i = 0; i < 3; i++) {
			scanf("%d", &nias[i]);
		}
		for (int i = 0; i < 3; i++) {
			scanf("%d", &ains[i]);
		}
		if (check(nias, ains)) {  //若刚开始就获胜则直接输出1.000
		printf("1.000\n");
		continue;
		}
		//t1用来临时存放nias,t2用来临时存放ains,因为中间要对数组进行改变,要一直保持nias和ains的只读性
		//cou用来记录获胜次数
		int t1[3], t2[3], cou;
		double maxn = -1;
		for (int i = 0; i < 3; i++) {
			memcpy(t1, nias, size);
			memcpy(t2, ains, size);
			cou = 0;
			for (t1[i] = 1; t1[i] <= 6; t1[i]++) {  //枚举每个骰子
				if (check(t1, t2)) {
					cou++;
				}
			}
			maxn = MAX(maxn, 1.0 * cou / 6);  //不断取大值
		}
		printf("%.3f\n", maxn);
		
	}
	return 0;
}




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值