week9-东东学打牌
Posted liuzhuan-xingyun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了week9-东东学打牌相关的知识,希望对你有一定的参考价值。
问题描述:
最近,东东沉迷于打牌。所以他找到 HRZ、ZJM 等人和他一起打牌。由于人数众多,东东稍微修改了亿下游戏规则:
所有扑克牌只按数字来算大小,忽略花色。
每张扑克牌的大小由一个值表示。A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K 分别指代 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13。
每个玩家抽得 5 张扑克牌,组成一手牌!(每种扑克牌的张数是无限的,你不用担心,东东家里有无数副扑克牌)
理所当然地,一手牌是有不同类型,并且有大小之分的。
举个栗子,现在东东的 “一手牌”(记为 α),瑞神的 “一手牌”(记为 β),要么 α > β,要么 α < β,要么 α = β。
那么这两个 “一手牌”,如何进行比较大小呢?首先对于不同类型的一手牌,其值的大小即下面的标号;对于同类型的一手牌,根据组成这手牌的 5 张牌不同,其值不同。下面依次列举了这手牌的形成规则:
大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。
对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。
两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。
三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。
三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。
炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。
顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。
龙顺:5 张牌分别为 10、J、Q、K、A。
作为一个称职的魔法师,东东得知了全场人手里 5 张牌的情况。他现在要输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。
请你告诉东东,全场人的排名
input:
输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。
output:
对于每组测试数据,输出 n 行,即这次全场人的排名。
样例输入:
3
DongDong AAA109
ZJM 678910
Hrz 678910
1
2
3
4
样例输出:
Hrz
ZJM
DongDong
思路:
这道题的关键在于数据的多关键字排序。
若两个人的一手牌种类不同,则先输出优先级高的名字,如果两个人的一手牌种类相同,则还有其他的比较标准。如果也相同,则就按名字先输出字典序小的。则我们可以在玩家结构题中重载<,如果两个人手牌的权重不同,则按权重的降序排序,如果两个人手牌权重相同,根据不同的手牌有另外的比较方法,若也相同,则按名字的升序排序。
代码:
1 #include<iostream> 2 #include<string> 3 #include<map> 4 #include<algorithm> 5 using namespace std; 6 struct player{//玩家结构体 7 string name;//名字 8 int p[6];//一手牌 9 int weight;//权重 10 bool operator < (const player pl)const 11 {//重载< 12 if(weight!=pl.weight) //若权重不同,按降序排序 13 return weight>pl.weight; 14 else if(weight==1&&pl.weight==1) 15 {//若权重都等于1,比较一手牌的点数之和,按降序排序 16 int pl1=0,pl2=0; 17 for(int i=1;i<=5;i++) 18 { 19 pl1+=p[i]; 20 pl2+=pl.p[i]; 21 } 22 if(pl1!=pl2) 23 return pl1>pl2; 24 else//如果也相同,则按名字升序排序 25 return name<pl.name; 26 } 27 else if(weight==2&&pl.weight==2) 28 {//如果权重为2 29 int a[14],b[14]; 30 for(int i=1;i<=13;i++) 31 a[i]=b[i]=0; 32 for(int i=1;i<=5;i++) 33 { 34 a[p[i]]++; 35 b[pl.p[i]]++; 36 } 37 int d1,d2,al1,al2; 38 d1=d2=al1=al2=0; 39 for(int i=1;i<=13;i++) 40 {//求出每个玩家的一对的点数大小和其余三张牌的点数和 41 if(a[i]==1) al1+=i; 42 else if(a[i]==2) d1=i; 43 if(b[i]==1) al2+=i; 44 else if(b[i]==2) d2=i; 45 } 46 if(d1!=d2) return d1>d2;//按一对的点数降序排列 47 else if(al1!=al2) return al1>al2;//按其余三张牌的点数和降序 48 else return name<pl.name;//按名字升序 49 } 50 else if(weight==3&&pl.weight==3) 51 { 52 int a[14],b[14]; 53 for(int i=1;i<=13;i++) 54 a[i]=b[i]=0; 55 for(int i=1;i<=5;i++) 56 { 57 a[p[i]]++;b[pl.p[i]]++; 58 } 59 int d1[2],d2[2],al1,al2,f1,f2; 60 f1=f2=al1=al2=0; 61 for(int i=1;i<=13;i++) 62 { 63 if(a[i]==1) al1=i;//求出另一张单排的点数 64 else if(a[i]==2)//求出两个二对的点数 65 d1[f1++]=i; 66 if(b[i]==1) al2=i; 67 else if(b[i]==2) 68 d2[f2++]=i; 69 } 70 int mx1,mx2,mn1,mn2; 71 mx1=mx2=mn1=mn2=0; 72 if(d1[0]>d1[1]) 73 { 74 mx1=d1[0];mn1=d1[1]; 75 } 76 else 77 { 78 mx1=d1[1];mn1=d1[0]; 79 } 80 if(d2[0]>d2[1]) 81 { 82 mx2=d2[0];mn2=d2[1]; 83 } 84 else 85 { 86 mx2=d2[1];mn2=d2[0]; 87 } 88 if(mx1!=mx2) return mx1>mx2;//按二对中点数比较大的降序 89 else if(mn1!=mn2) return mn1>mn2;//二对中点数比较小的降序 90 else if(al1!=al2) return al1>al2;//单牌降序排列 91 else return name<pl.name;//名字升序排列 92 } 93 else if(weight==4&&pl.weight==4) 94 { 95 int a[14],b[14]; 96 for(int i=1;i<=13;i++) 97 a[i]=b[i]=0; 98 for(int i=1;i<=5;i++) 99 { 100 a[p[i]]++;b[pl.p[i]]++; 101 } 102 int d1,d2,al1,al2; 103 d1=d2=al1=al2=0; 104 for(int i=1;i<=13;i++) 105 { 106 if(a[i]==1) al1+=i;//找到除了三个的另外两张牌点数和 107 else if(a[i]==3) d1=i;//找到三个 108 if(b[i]==1) al2+=i; 109 else if(b[i]==3) d2=i; 110 } 111 if(d1!=d2) return d1>d2;//按三个点数降序排列 112 else if(al1!=al2) return al1>al2;//其余两张牌点数和的降序排列 113 else return name<pl.name;//名字升序排列 114 } 115 else if(weight==5&&pl.weight==5) 116 { 117 int a[14],b[14]; 118 for(int i=1;i<=13;i++) 119 a[i]=b[i]=0; 120 for(int i=1;i<=5;i++) 121 { 122 a[p[i]]++;b[pl.p[i]]++; 123 } 124 int d1,d2,al1,al2; 125 for(int i=1;i<=13;i++) 126 { 127 if(a[i]==2) al1=i;//找到三个和一对 128 else if(a[i]==3) d1=i; 129 if(b[i]==2) al2=i; 130 else if(b[i]==3) d2=i; 131 } 132 if(d1!=d2) return d1>d2;//按三个点数降序排列 133 else if(al1!=al2) return al1>al2;//按一对降序排列 134 else return name<pl.name;//按名字升序排列 135 } 136 else if(weight==6&&pl.weight==6) 137 { 138 int a[14],b[14]; 139 for(int i=1;i<=13;i++) 140 a[i]=b[i]=0; 141 for(int i=1;i<=5;i++) 142 { 143 a[p[i]]++;b[pl.p[i]]++; 144 } 145 int d1,d2,al1,al2; 146 for(int i=1;i<=13;i++) 147 { 148 if(a[i]==1) al1=i;//出炸弹外的牌的点数 149 else if(a[i]==4) d1=i;//炸弹的点数 150 if(b[i]==1) al2=i; 151 else if(b[i]==4) d2=i; 152 } 153 if(d1!=d2) return d1>d2;//按炸弹点数降序 154 else if(al1!=al2) return al1>al2;//按单牌点数降序 155 else return name<pl.name;//按名字升序 156 } 157 else if(weight==7&&pl.weight==7) 158 { 159 int mx1,mx2; 160 mx1=mx2=0; 161 for(int i=1;i<=5;i++) 162 { 163 if(p[i]>mx1) mx1=p[i]; 164 if(pl.p[i]>mx2) mx2=pl.p[i]; 165 } 166 if(mx1!=mx2) return mx1>mx2;//按顺子最大值降序 167 else return name<pl.name;//按名字升序 168 } 169 else 170 return name<pl.name;//龙顺都是相同的,所以按名字升序 171 } 172 }; 173 player pler[100010]; 174 int n; 175 int solve(int s) 176 {//求出一组牌的种类,和打牌游戏2思想类似 177 int temp[6]; 178 for(int i=1;i<=5;i++) 179 temp[i]=pler[s].p[i]; 180 bool t1[14]; 181 int t2[14]; 182 for(int i=1;i<=13;i++) 183 { 184 t1[i]=false; 185 t2[i]=0; 186 } 187 int mx=0; 188 for(int i=1;i<=5;i++) 189 { 190 int te=temp[i]; 191 t1[te]=true; 192 t2[te]++; 193 if(mx<te) mx=te; 194 } 195 int tw,th,fo; 196 tw=th=fo=0; 197 for(int i=1;i<=13;i++) 198 { 199 if(t2[i]==2) tw++; 200 else if(t2[i]==3) th++; 201 else if(t2[i]==4) fo++; 202 } 203 if(t1[1]&&t1[10]&&t1[11]&&t1[12]&&t1[13]) 204 return 8; 205 if(mx>=5) 206 { 207 if(t1[mx]&&t1[mx-1]&&t1[mx-2]&&t1[mx-3]&&t1[mx-4]) 208 return 7; 209 } 210 if(fo==1) 211 return 6; 212 if(th==1&&tw==1) 213 return 5; 214 if(th==1&&tw==0) 215 return 4; 216 if(tw==2) 217 return 3; 218 if(tw==1) 219 return 2; 220 return 1; 221 } 222 int main() 223 { 224 map<char,int> mm; 225 mm[‘A‘]=1; 226 mm[‘J‘]=11; 227 mm[‘Q‘]=12; 228 mm[‘K‘]=13;//利用map将字母转化为点数 229 cin>>n; 230 for(int j=1;j<=n;j++) 231 { 232 string nn; 233 cin>>nn; 234 pler[j].name=nn; 235 string pai; 236 cin>>pai; 237 int flag=1; 238 for(int i=0;i<pai.size();i++)//读入一组牌并转为数字 239 { 240 if(pai[i]>=49&&pai[i]<=57) 241 { 242 if(pai[i]==49) 243 { 244 if(pai[i+1]==48) 245 { 246 pler[j].p[flag]=10; 247 flag++; 248 i++; 249 continue; 250 } 251 else 252 { 253 pler[j].p[flag]=1; 254 flag++; 255 continue; 256 } 257 } 258 else 259 { 260 pler[j].p[flag]=pai[i]-48; 261 flag++; 262 continue; 263 } 264 } 265 else 266 { 267 int temp=mm[pai[i]]; 268 pler[j].p[flag]=temp; 269 flag++; 270 } 271 } 272 int ww=solve(j);//求出权重 273 pler[j].weight=ww; 274 } 275 sort(pler+1,pler+n+1);//排序输出 276 for(int i=1;i<=n;i++) 277 { 278 cout<<pler[i].name<<endl; 279 } 280 return 0; 281 }
以上是关于week9-东东学打牌的主要内容,如果未能解决你的问题,请参考以下文章