您的位置:首页 > 理论基础

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

2015-12-01 09:57 337 查看
玩骰子

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: