【问题描述】
斯诺克台球是一项古老而又时尚的运动,使用长方形球桌,台面四角以及两长边中心位置各有一个球袋,使用的球分为1个白球,15个红球和6个彩球共22个球。
其中母球(白球)1只,目标球21只。目标球中:红球15只各1分、黄球1只2分、绿球1只3分、咖啡球1只4分、蓝球1只5分、粉球1只6分、黑球1只7分。
选手需要使用球杆撞击母球去击打目标球来完成得分,每局开始时总是先从红球开始。击球顺序为先打进红球(每次击打允许多个红球同时落袋),然后必须任意指定一个目标彩球击打,如果该彩球被打进(打进后需要再摆回),然后接着击打红球,直到红球全部落袋,然后以黄、绿、咖啡、蓝、粉红、黑的顺序逐个击球(不再摆回),最后以得分高者为胜。任何时候红球落袋都不再摆回,任何时候因犯规导致彩球落袋,彩球必须摆回。
斯诺克比赛由双方轮流击打,必须击打合规的目标球,打进则本方得到相应的分数并继续击打,未打进或犯规轮换为对方击打,未打进不得分,犯规将进行罚分处理。
犯规规则如下:
1. 当击打目标球时,如果先击打到或同时击打到一个或多个其他颜色的球,或者有其他颜色的球落袋,或者打空(未击打到任何球),则视为犯规。此时需要比较目标球的分值和与本犯规相关的其他颜色的球的分值,取其中最高的分值,如果该分值小于4,则对方加4分,否则对方加该分值。
2. 当击打红球落袋后,继续击打任意彩球时打空,即未打击到任何球,对方加4分。
相比正式的斯诺克比赛,本问题对规则进行了简化,任何时候都可以结束比赛并计算比赛结果,不考虑白球落袋的情况。
信息化时代的智能台球桌能自动记录实际比赛时的击打记录,并传送到后台,但该记录仅仅是流水记录,并且无参赛选手的任何信息,需要你编程计算每场比赛的比分,同时需要计算单杆100分及以上的情况(单杆得分是指选手一次连续击打所得分数之和)。
【输入形式】
输入第一行为正整数t (t≤100),表示有t组测试数据,每组数据代表一局比赛。
在输入中,球的颜色表示为:
r-红色球 y-黄色球 g-绿色球 c-咖啡色球 b-蓝色球 p-粉红球 B-黑色球
接下来的每组数据包括若干行,每一行为一次击打的结果,为智能球桌记录下来的流水记录,每组数据最后一行为-1,表示每组数据的结束。
流水记录包含用空格分隔的2个部分:
首先撞到的球 落袋球及数量
第一部分“首先撞到的球”为一个字符串,可以是“rygcbpB”中1个或多个字符组合(可能有多个字符“r”),或为字符串“NULL”。为“NULL”时,第二部分必为空,表示该次击打未撞击到任何球也没有任何球落袋。当红球落袋后继续击打任意彩球时,该部分为“ygcbpB”中的任意单个字符时都认为是合规的目标球。
第二部分“落袋球及数量”为一个字符串,例如“r2gb”,代表本次击打有两个红球落袋,以及绿球和篮球落袋,红色球r后面有数字(大于0小于16),表示红球的落袋数,其他彩球后无数字。该部分可以为空,表示本次击打无球落袋。
比赛在A与B之间进行,每局比赛总是由A先开球。
【输出形式】
输出为t+1行,前t行每行输出用冒号分隔的两个整数,表示每局比赛A与B之间的比分;最后一行输出用冒号分隔的两个整数,表示t局比赛之后A与B之间获得的单杆100分及以上的次数之比(单杆得分是指选手一次连续击打所得分数之和)。
【样例输入】
3 r r1 B r r2 c c r r1 b g -1 rp r1 r br2B NULL r r12 y y g p -1 rr r3 NULL r r1 yg y -1
【样例输出】
6:7 13:24 7:5 0:0
【样例说明】
第一局比赛:
A击打红球,打进1个红球,得1分,比分为 1:0
A继续击打任意彩球,打到黑球,未打进,不得分,比分为1:0
轮换为B击打红球,打进两个红球,得2分,比分为1:2
B继续击打任意彩球,打到咖啡球,打进咖啡球,咖啡球摆回,得4分,比分为1:6
B继续击打红球,打进一个红球,得1分,比分为1:7
B继续击打任意彩球,打到蓝球,打进绿球,犯规,取分值最大者蓝球,绿球摆回,对方加5分,比分为6:7
-1比赛结束
第二局比赛:
A击打红球,首先打到红球和粉球,犯规,打进1个红球和咖啡球,犯规,咖啡球摆回,取分值最大的粉球,对方加6分,比分为0:6
B击打红球,首先打到红球,打进蓝球、2个红球和黑球,犯规,蓝球和黑球摆回,取分值最大的黑球,对方加7分,比分为7:6
A击打红球,未打到任何球,犯规,对方加4分,比分为7:10
B击打红球,打到红球,打进12个红球,加12分,比分为7:22
B击打任意彩球,打到黄球,打进黄球,黄球摆回,得2分,比分为7:24
B击打黄球,打到绿球,打进粉球,犯规,粉球摆回,对方加6分,比分为13:24
-1比赛结束
第三局比赛:
A击打红球,打到2个红球,打进3个红球,加3分,比分为3:0
A击打任意彩球,打空,未打到任何球,对方加4分,比分为3:4
B击打红球,打到1个红球,打进1个红球,加1分,比分为3:5
B击打任意彩球,打到黄球和绿球,打进黄球,犯规,黄球摆回,取分值最高的绿球,绿球分值小于4,对方加4分,比分为7:5
-1比赛结束
3局比赛中无人单杆得分过100,最后一行输出0:0
【思路】
这道题写了好久,主要还是一开始没有能完全弄清题目的意思!
有几个值得注意的点:
1.只要击球或者落球犯规,都是从所有球(包括击打球,落球,目标球)中找分值最大的
2.红球落袋必定计数(任何情况都要)
3.单杆得分是一次连续击打,不是一局总分【因为这个点儿没搞清,弄了老久~
4.如果打红球的时候,没有犯规,并且打进最后一个红球,这时候要先来个【自由彩球】,才能到 顺序彩球(具体规则一定要仔细看样例
代码长,大概表述一下就是:
分出:【 A打红,A打彩;B打红,B打彩 】 四种情况,来回调用直至结束
其中彩球又分为【自由彩球,顺序彩球】 两种,通过前一个击打的球确定
每次要切换到对手打的时候,把自己单杆得分看一下,并且两边单杆得分都清零
一道麻烦的题目~耐心点才能拿下~
【AC代码】
#include<string>
#include<iostream>
#include<sstream>
#include<stack>
#include<vector>
using namespace std;
int ball_score(char a){
switch(a){
case 'r':{
return 1;
break;
}
case 'y':{
return 2;
break;
}
case 'g':{
return 3;
break;
}
case 'c':{
return 4;
break;
}
case 'b':{
return 5;
break;
}
case 'p':{
return 6;
break;
}
case 'B':{
return 7;
break;
}
default:{
return 0;
break;
}
}
}
int ball[8];
int ball_num(char a){
return ball[ball_score(a)];
}
void init_ball_num(){
ball[1]=15;
for(int i=2;i<=7;i++) ball[i]=1;
}
int A_100_times=0,B_100_times=0;//(单杆得分是指选手一次连续击打所得分数之和)!!! 【 不是一局的总分!!!】
int A_score,B_score;
void A_red();
void B_red();
void A_color(char fa);
void B_color(char fa);
int A_hit_score=0,B_hit_score=0;
void A_red(){
if(ball_num('r')==0) {
A_color('r'); //红球没了,只能是按顺序击打彩球
return;
}
if(B_hit_score>=100){
//cout<<endl<<endl<<"B_MARK__100"<<endl<<endl;
B_100_times++;
B_hit_score=0;
//cout<<endl<<"@@@@@a_red: "<<A_hit_score<<" "<<B_hit_score<<endl;
}
string condition;
getline(cin,condition);
if(condition=="-1") {
if(A_hit_score>=100) A_100_times++; //在自己连续击打的时候结束
A_hit_score=0;B_hit_score=0;//初始化双方连续击打分
cout<<A_score<<":"<<B_score<<endl;
return; //本局比赛结束;
}
if(condition=="NULL") {//打空了 犯规
B_score+=4;
B_hit_score=0;
B_red();
} else if(condition.find(' ')!=string::npos ){ //有打球,有落入
string hit,drop;
hit=condition.substr(0,condition.find(' '));
drop=condition.substr(condition.find(' ')+1,condition.size() - condition.find(' '));
int flag1=1;
int maxi1=4;
for(int i=0;i<hit.size() ;i++){ //看击打有没有犯规
if(hit[i]!='r') flag1=0;
if(maxi1<ball_score(hit[i])) maxi1=ball_score(hit[i]);
}
int flag2=1;
int maxi2=4; //看落球有没有犯规
for(int i=0;i<drop.size() ;i++){
if(drop[i]!='r'){
if(drop[i]<'0'||drop[i]>'9'){
flag2=0;
}
}
if(maxi2<ball_score(drop[i])) maxi2=ball_score(drop[i]);
}
//不管犯不犯规 红球落入了就得减去
int r_num=0;
if(drop.find('r')!=string::npos ){//有红球落入
int pos=drop.find('r');
vector<int> v;
for(int i=pos+1;i<drop.size() ;i++) {
if(drop[i]>='0'&&drop[i]<='9') v.push_back(drop[i]-'0');
}
if(v.size()==1) {
r_num+=v[0];
ball[ball_score('r')]-=r_num;
}
else {
r_num+=v[0]*10 + v[1];
ball[ball_score('r')]-=r_num;
}
}
if(flag1==0 || flag2==0){ //两样都犯规了 比较出最大分数给对方加上 计算掉入的红球
B_score+=max(maxi1,maxi2);
B_hit_score=0;
B_red();
}else { //没有犯规
A_hit_score+=r_num;
A_score+=r_num;
A_color('f'); //常规自由球
}
}else { //只打了球,没落入
int flag=1;
for(int i=0;i<condition.size() ;i++){
if(condition[i]!='r'){
flag=0;
}
}
if(flag==1){ //打得全是红球 因为没落入 所以没分 红球也没有少
B_hit_score=0;
B_red();
}else{ //打到了其他球, 犯规 对方加分
int maxi3=4;
for(int i=0;i<condition.size() ;i++){
if(ball_score(condition[i])>maxi3) maxi3=ball_score(condition[i]);
}
B_score+=maxi3;
B_hit_score=0;
B_red();
}
}
}
void A_color(char fa){ //要判断当前打自由彩球还是顺序彩球 记录上一球
if(B_hit_score>=100){
//cout<<endl<<endl<<"B_MARK__100"<<endl<<endl;
B_100_times++;
B_hit_score=0;
//cout<<endl<<"@@@@@a_color: "<<A_hit_score<<" "<<B_hit_score<<endl;
}
string condition;
getline(cin,condition);
if(condition=="-1" ){
if(A_hit_score>=100) A_100_times++; //在自己连续击打的时候结束
A_hit_score=0;B_hit_score=0;
cout<<A_score<<":"<<B_score<<endl;
return; //本局比赛结束;
}
if(fa=='f') { //自由彩球
if(condition=="NULL") { //打空了 犯规
B_score+=4;
B_hit_score=0;
B_red();
} else if(condition.find(' ')!=string::npos ){ //有打球,有落入
string hit,drop;
hit=condition.substr(0,condition.find(' '));
drop=condition.substr(condition.find(' ')+1,condition.size() - condition.find(' '));
int r_num=0; //无论如何,只要有红球落入,就要计算
if(drop.find('r')!=string::npos ){//有红球落入
int pos=drop.find('r');
vector<int> v;
for(int i=pos+1;i<drop.size() ;i++) {
if(drop[i]>='0'&&drop[i]<='9') v.push_back(drop[i]-'0');
}
if(v.size()==1) {
r_num+=v[0];
ball[ball_score('r')]-=r_num;
}
else {
r_num+=v[0]*10 + v[1];
ball[ball_score('r')]-=r_num;
}
}
int flag1=1; //看击打有没有犯规
int maxi1=4;
if(hit=="r"||hit.size()>1){
flag1=0;
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi1) maxi1=ball_score(hit[i]);
}
}
if(flag1==0){//击球犯规,在击球和落球里面找个最大的给对方加分
for(int i=0;i<drop.size();i++){
if(ball_score(drop[i])>maxi1) maxi1=ball_score(drop[i]);
}
B_score+=maxi1;
B_hit_score=0;
B_red();
} else{ //击球没犯规,只打了一个彩球
if(drop==hit){ //落球也完全一样 ,加分继续打红球
A_hit_score+=ball_score(drop[0]);
A_score+=ball_score(drop[0]);
A_red();
}else{ //落球多了些东西,给对方加最大分
int maxi3=4;
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi3) maxi3=ball_score(hit[i]);
}
for(int i=0;i<drop.size();i++){
if(ball_score(drop[i])>maxi3) maxi3=ball_score(drop[i]);
}
B_score+=maxi3;
B_hit_score=0;
B_red();
}
}
} else{//只打了球,没落入
if(condition=="r"||condition.size() >1) {//打到了多个球或者打到了红球 没进
int maxi=4;
for(int i=0;i<condition.size() ;i++){
if(ball_score(condition[i])>maxi) maxi=ball_score(condition[i]);
}
B_score+=maxi;
B_hit_score=0;
B_red();
} else{ //打到单个彩球 但没进
B_hit_score=0;
B_red();
}
}
} else { //顺序彩球
string sub="rygcbpB";
string goal=sub.substr(sub.find(fa)+1,1);
char c_goal=sub[sub.find(fa)+1 ];
if(condition=="NULL") { //打空了,犯规,对方加分,按顺序打
B_score+=4;
B_hit_score=0;
B_color(fa);
} else if(condition.find(' ')!=string::npos ){ //有打球,有落入
string hit,drop;
hit=condition.substr(0,condition.find(' '));
drop=condition.substr(condition.find(' ')+1,condition.size() - condition.find(' '));
if( hit==goal && hit==drop ) { //目标, 击打,落入都一样
A_hit_score+=ball_score(c_goal);
A_score+=ball_score(c_goal);//分数增加
ball[ball_score(c_goal)]--; //球数减少
A_color(c_goal); //继续按照顺序击打
} else{//击球或者落球犯规,在所有球里面找最大的 (包括目标球)
int maxi3=max(4,ball_score(c_goal));
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi3) maxi3=ball_score(hit[i]);
}
for(int i=0;i<drop.size();i++){
if(ball_score(drop[i])>maxi3) maxi3=ball_score(drop[i]);
}
B_score+=maxi3;
B_hit_score=0;
B_color(fa);
}
}else { //有打球,没落入
string hit=condition;
if(hit==goal){
B_hit_score=0;
B_color(fa);
}else {
int maxi=4;
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi) maxi=ball_score(hit[i]);
}
B_score+=maxi;
B_hit_score=0;
B_color(fa);
}
}
}
}
void B_red(){
if(ball_num('r')==0) {
B_color('r'); //红球没了,只能是按顺序击打彩球
return;
}
if(A_hit_score>=100){
//cout<<endl<<endl<<"A_MARK__100"<<endl<<endl;
A_100_times++;
A_hit_score=0;
//cout<<endl<<"@@@@@b_red: "<<A_hit_score<<" "<<B_hit_score<<endl;
}
string condition;
getline(cin,condition);
if(condition=="-1") {
if(B_hit_score>=100) B_100_times++; //在自己连续击打的时候结束
A_hit_score=0;B_hit_score=0;
cout<<A_score<<":"<<B_score<<endl;
return; //本局比赛结束;
}
if(condition=="NULL") {//打空了 犯规
A_score+=4;
A_hit_score=0;
A_red();
} else if(condition.find(' ')!=string::npos ){ //有打球,有落入
string hit,drop;
hit=condition.substr(0,condition.find(' '));
drop=condition.substr(condition.find(' ')+1,condition.size() - condition.find(' '));
//cout<<endl<<"@@@@"<<hit<<"@@"<<drop<<endl;
int flag1=1;
int maxi1=4;
for(int i=0;i<hit.size() ;i++){ //看击打有没有犯规
if(hit[i]!='r') flag1=0;
if(maxi1<ball_score(hit[i])) maxi1=ball_score(hit[i]);
}
int flag2=1;
int maxi2=4; //看落球有没有犯规
for(int i=0;i<drop.size() ;i++){
if(drop[i]!='r'){
if(drop[i]<'0'||drop[i]>'9'){
flag2=0;
}
}
if(maxi2<ball_score(drop[i])) maxi2=ball_score(drop[i]);
}
//不管犯不犯规 红球落入了就得减去
int r_num=0;
if(drop.find('r')!=string::npos ){//有红球落入
int pos=drop.find('r');
vector<int> v;
for(int i=pos+1;i<drop.size() ;i++) {
if(drop[i]>='0'&&drop[i]<='9') v.push_back(drop[i]-'0');
}
if(v.size()==1) {
r_num+=v[0];
ball[ball_score('r')]-=r_num;
}
else {
r_num+=v[0]*10 + v[1];
ball[ball_score('r')]-=r_num;
}
}
if(flag1==0&&flag2==0){ //两样都犯规了 比较出最大分数给对方加上 计算掉入的红球
A_score+=max(maxi1,maxi2);
A_hit_score=0;
A_red();
}else if(flag1==0){ //击球犯规 @@@@@@@@@@@@@@存疑
A_score+=max(maxi1,maxi2);
A_hit_score=0;
A_red();
}else if(flag2==0){ //落球犯规
A_score+=max(maxi1,maxi2);
A_hit_score=0;
A_red();
}else { //没有犯规
B_hit_score+=r_num;
B_score+=r_num;
B_color('f'); //常规自由球
}
}else { //只打了球,没落入
int flag=1;
for(int i=0;i<condition.size() ;i++){
if(condition[i]!='r'){
flag=0;
}
}
if(flag==1){ //打得全是红球 因为没落入 所以没分 红球也没有少
A_hit_score=0;
A_red();
}else{ //打到了其他球, 犯规 对方加分
int maxi3=4;
for(int i=0;i<condition.size() ;i++){
if(ball_score(condition[i])>maxi3) maxi3=ball_score(condition[i]);
}
A_score+=maxi3;
A_hit_score=0;
A_red();
}
}
}
void B_color(char fa){
if(A_hit_score>=100){
//cout<<endl<<endl<<"A_MARK__100"<<endl<<endl;
A_100_times++;
A_hit_score=0;
//cout<<endl<<"@@@@@b_color: "<<A_hit_score<<" "<<B_hit_score<<endl;
}
string condition;
getline(cin,condition);
if(condition=="-1" ){
if(B_hit_score>=100) B_100_times++; //在自己连续击打的时候结束
A_hit_score=0;B_hit_score=0;
cout<<A_score<<":"<<B_score<<endl;
return; //本局比赛结束;
}
if(fa=='f') { //自由彩球
if(condition=="NULL") { //打空了 犯规
A_score+=4;
A_hit_score=0;
A_red();
} else if(condition.find(' ')!=string::npos ){ //有打球,有落入
string hit,drop;
hit=condition.substr(0,condition.find(' '));
drop=condition.substr(condition.find(' ')+1,condition.size() - condition.find(' '));
int r_num=0; //无论如何,只要有红球落入,就要计算
if(drop.find('r')!=string::npos ){//有红球落入
int pos=drop.find('r');
vector<int> v;
for(int i=pos+1;i<drop.size() ;i++) {
if(drop[i]>='0'&&drop[i]<='9') v.push_back(drop[i]-'0');
}
if(v.size()==1) {
r_num+=v[0];
ball[ball_score('r')]-=r_num;
}
else {
r_num+=v[0]*10 + v[1];
ball[ball_score('r')]-=r_num;
}
}
int flag1=1; //看击打有没有犯规
int maxi1=4;
if(hit=="r"||hit.size()>1){
flag1=0;
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi1) maxi1=ball_score(hit[i]);
}
}
if(flag1==0){ //击球犯规,在击球和落球里面找个最大的给对方加分 击球犯规,落球一定犯规
for(int i=0;i<drop.size();i++){
if(ball_score(drop[i])>maxi1) maxi1=ball_score(drop[i]);
}
A_score+=maxi1;
A_hit_score=0;
A_red();
} else{ //击球没犯规,只打了一个彩球
if(drop==hit){ //落球也完全一样 ,加分继续打红球
B_hit_score+=ball_score(drop[0]);
B_score+=ball_score(drop[0]);
B_red();
}else{ //落球多了些东西犯规,给对方加最大分 (击打和落球中的最大分)
int maxi3=4;
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi3) maxi3=ball_score(hit[i]);
}
for(int i=0;i<drop.size();i++){
if(ball_score(drop[i])>maxi3) maxi3=ball_score(drop[i]);
}
A_score+=maxi3;
A_hit_score=0;
A_red();
}
}
} else{//只打了球,没落入
if(condition=="r"||condition.size() >1) {//打到了多个球或者打到了红球 没进
int maxi=4;
for(int i=0;i<condition.size() ;i++){
if(ball_score(condition[i])>maxi) maxi=ball_score(condition[i]);
}
A_score+=maxi;
A_hit_score=0;
A_red();
} else{ //打到单个彩球 但没进
A_hit_score=0;
A_red();
}
}
} else { //顺序彩球
string sub="rygcbpB";
string goal=sub.substr(sub.find(fa)+1,1);
char c_goal=sub[sub.find(fa)+1 ];
if(condition=="NULL") { //打空了,犯规,对方加分,按顺序打
A_score+=4;
A_hit_score=0;
A_color(fa);
} else if(condition.find(' ')!=string::npos ){ //有打球,有落入
string hit,drop;
hit=condition.substr(0,condition.find(' '));
drop=condition.substr(condition.find(' ')+1,condition.size() - condition.find(' '));
if( hit==goal && hit==drop ) { //目标, 击打,落入都一样
B_hit_score+=ball_score(c_goal);
B_score+=ball_score(c_goal);//分数增加
ball[ball_score(c_goal)]--; //球数减少
B_color(c_goal); //继续按照顺序击打
} else { //击球犯规,在所有球里面找最大的
// if(hit==goal && hit!=drop){
// int maxi=4;
// for(int i=0;i<drop.size();i++){
// if(ball_score(drop[i])>maxi) maxi=ball_score(drop[i]);
// }
// A_score+=maxi;
// A_color(fa);
// }else if(hit!=goal){
int maxi=max(4,ball_score(c_goal));
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi) maxi=ball_score(hit[i]);
}
for(int i=0;i<drop.size();i++){
if(ball_score(drop[i])>maxi) maxi=ball_score(drop[i]);
}
A_score+=maxi;
A_hit_score=0;
A_color(fa);
}
}else { //有打球,没落入
string hit=condition;
if(hit==goal){
A_hit_score=0;
A_color(fa);
}else {
int maxi=4;
for(int i=0;i<hit.size();i++){
if(ball_score(hit[i])>maxi) maxi=ball_score(hit[i]);
}
A_score+=maxi;
A_hit_score=0;
A_color(fa);
}
}
}
}
int main(){
int t;
cin>>t;
cin.get(); //吸收回车
while(t--){
A_score=0;B_score=0; //每局开始,双方分数清零
A_hit_score=0;B_hit_score=0; //击打得分清零
init_ball_num(); //球数初始化
A_red();
}
cout<<A_100_times<<":"<<B_100_times;
}
【写在后面】
觉得对你有帮助的话记得一键三连哦~(误
相关题目放在了【HNU CJ】专栏
如果有啥问题可以评论留言或者私我哦~