「Wdsr-2.5」琪露诺的算数游戏 题解 大模拟

题目链接 P7506 「Wdsr-2.5」琪露诺的算数游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

自己做出来的第一道大模拟,写篇题解纪念一下

对于每种牌型,可以用map来映射,也可以用整型值来表示,我选择后者

读牌输牌直接switch

几个重要的地方:

1.优先级问题,对于不同情况有不同的优先级,可以把各种牌型按优先级映射为从大到小的数字,然后比较大小判优先

2.double问题,注意double状态选最小,一个人如果用普通牌要出两轮

3.摸牌问题,可以对于出牌选择记录下标,然后把对应下标替换新牌

4.最最最最重要!!!除法的向下取整,如果是负数直接除是向上取整,可以用double强转后用floor函数

5.p可能会很大,对于一些极限值尽量设大一点

6.一个人手里有普通有特殊,如果出普通会输,他也会用特殊

然后就是用心码代码,耐心调,我还附赠了造数据的代码,可以对拍

//码力大模拟初体验
#include <bits/stdc++.h>
using namespace std;
#define min(x,y) x>y?y:x
#define max(x,y) x>y?x:y
#define clear(x) memset(x,0,sizeof(x))
const int sp = -1e5;
const int M = 5e6;
const int inf = 1e9;
/*
牌型定义:
A 直接为相应的数:1,2,99....
B 负数:-1,-19......
C 102 D 103 乘除法
E 100,149,199 即原数加上100
特殊牌:pass -123 turn -124 double -125
正好是按照优先级编的号 
*/
struct Player{//玩家
    char name[50];//名字
    int card[10];//卡牌
    Player(){
        clear(name);clear(card);
    }
};
Player player[50];
typedef long long ll;
inline int read(){
    int x=0,f=0;char c=getchar();
    while(!isdigit(c)){
        if(c=='-') f=1;
        c=getchar();
    }
    do{
        x=(x<<1)+(x<<3)+(c^48);
    }while(isdigit(c=getchar()));
    return f?-x:x;
}
inline void print(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);putchar(x%10^48);
}
int getcard(char s[]){//把字符串型的牌转换为设定的整数型牌
    int f=0;
    int l=strlen(s);
    if(s[0]=='A'){
        for(int i=1;i<l;i++) f=f*10+s[i]-'0';
        return f;
    }
    if(s[0]=='B'){
        for(int i=1;i<l;i++) f=f*10+s[i]-'0';
        return -f;
    }
    if(s[0]=='C'){
        return 102;
    }
    if(s[0]=='D'&&s[1]!='O'){//注意是double 还是 D
        return 103;
    }
    if(s[0]=='E'){
        for(int i=1;i<l;i++) f=f*10+s[i]-'0';
        return f+100;
    }
    if(s[0]=='P') return -123;
    if(s[0]=='T') return -124;
    if(s[0]=='D') return -125;
}
void Print_Card(int x){//把整形的牌转成字符串输出
    switch(x){
        case 1:printf("A1");break;
        case 2:printf("A2");break;
        case 5:printf("A5");break;
        case 9:printf("A9");break;
        case 19:printf("A19");break;
        case 49:printf("A49");break;
        case 99:printf("A99");break;
        case -1:printf("B1");break;
        case -9:printf("B9");break;
        case -19:printf("B19");break;
        case 102:printf("C2");break;
        case 103:printf("D2");break;
        case 100:printf("E0");break;
        case 149:printf("E49");break;
        case 199:printf("E99");break;
        case -123:printf("PASS");break;
        case -124:printf("TURN");break;
        case -125:printf("DOUBLE");break;
        default:printf("ERORR");break;
    }
}
int div(int p){//细节,负数的向下取整,比如-1/2是-1,但直接除是0,所以可以用double型强转后用floor函数向下取整
    double c=1.0*p,d=2.0;
    int x=floor(c/d);
    return x;
}
int Update_P(int p,int k){//更新p的值
    //p是现在p的值,k是将要进行的操作
    if(k>=0){
        if(k<100) return p+k;//+
        else{
            if(k==102) return p*2;//*
            else if(k==103){
                return div(p);//
            }
            else return k-100;//std
        }
    }
    else{
        if(k>-100) return p+k;//-
        else return sp;//special
    }
    return sp;//useless
}
// *:4 +:3 -:2 /:1 std:0 sp:5
/*
优先级问题:
有两种优先级:正常优先级和double状态下优先级
根据题意,把正常优先级设为 *:4 +:3 -:2 /:1 std:0 
double优先级设为 /:4 -:3 +:2 *:1 std:0
*/
int Big_Type(int x){
    //正常优先级
    if(x==102) return 4;//*
    if(x==103) return 1;// /
    if(x>=100) return 0;//std
    if(x>0) return 3;//+
    if(x>-100) return 2;//-
    return 5;
}
int Small_Type(int x){
    //double优先级
    if(x==102) return 1;//*
    if(x==103) return 4;// /
    if(x>=100) return 0;//std
    if(x>0) return 2;//+
    if(x>-100) return 3;//-
    return 5;
}
int P;// 储存器P
int n,m,k;
int deck[M];//牌堆
int dtot;//排队指针
char temp[25];//输入用临时数组
void Before_Game(){//初始化读牌
      for(int i=1;i<=n;i++){
        scanf("%s",player[i].name);
        for(int j=1;j<=3;j++){
            scanf("%s",temp);
            player[i].card[j]=getcard(temp);
        }
    }
    for(int i=1;i<=k;i++){
        scanf("%s",temp);
        deck[i]=getcard(temp);
    }
}
int Is_Special(int k){//判断一个人有无特殊牌
    for(int i=1;i<=3;i++) if(player[k].card[i]<-100) return i;
    return 0;
}
int Is_Normal(int k){//判断一个人有无普通牌
    for(int i=1;i<=3;i++) if(player[k].card[i]>=-100) return i;
    return 0;
}
bool Is_Lost(int p,int k){//判断一个人是不是输了
    if(Is_Special(k)) return 0;
    for(int i=1;i<=3;i++){
        int x=player[k].card[i];
        if(Update_P(p,x)<=99) return 0;
    }
    return 1;
}
bool Maybe_Lost(int p,int k){//判断一个人手里的普通牌会不会让他输掉
    for(int i=1;i<=3;i++){
        int x=player[k].card[i];
        if(x<=-100) continue;
        if(Update_P(p,x)<=99) return 0;
    }
    return 1;
}
int Biggest_Decision(int p,int k){//使P最大的选择
    int maxx=-inf,pos,type;
    for(int i=1;i<=3;i++){
        int x=player[k].card[i];//牌型
        int res=Update_P(p,x);//使用后P的值
        if(res==sp) continue;//特殊牌
        if(res>99) continue;//会输
        if(res>=maxx){//大了
            if(res>maxx) pos=i,maxx=res,type=Big_Type(x);//真大了,更新
            else{//相等
                int tp=Big_Type(x);//取优先级
                if(tp>type) pos=i,type=tp;//优先级比之前的大,更新
            }
        }
    }
    return pos;//返回下标位置
}
int Smallest_Decision(int p,int k){
    //同上,改成最小即可
    int minn=inf,pos,type;
    for(int i=1;i<=3;i++){
        int x=player[k].card[i];
        int res=Update_P(p,x);
        if(res==sp) continue;
        if(res>99) continue;
        if(res<=minn){
            if(res<minn) pos=i,minn=res,type=Small_Type(x);
            else{//equal
                int tp=Small_Type(x);
                if(tp>type) pos=i,type=tp;
            }
        }
    }
    return pos;
}
int Special_Decision(int k){
    //特殊牌的选择
    int pos,maxx=-inf;
    for(int i=1;i<=3;i++){
        int x=player[k].card[i];
        if(x>maxx&&x<-100) pos=i,maxx=x; 
        //按照特殊牌的优先顺序
    }
    return pos;//返回下标
}
int dir=1;//1 顺 -1 逆
int now=1;//位置
int rounds;//轮数
int next_one(int pos,int dir){//移动到下一个人
    int x=(pos+dir+n)%n;
    if(x==0) return n;
    return x;
}
void Round_Start(){//一轮游戏
    P=0;dir=1;//初始化
    rounds++;
    int again=0;//上一个人再来一次,double用
    printf("Round %d:\n",rounds);
    int Is_double=0;//是不是double状态
    int first=1;//是不是第一个人
    while(1){
        if(!first) now=next_one(now,dir);//移动到下一个人
        first=0;
        if(again) now=again,again=0;//再来一次
        if(Is_Lost(P,now)){//输了
            printf("%s lost the game.\n",player[now].name);
            break;
        }
        if(Is_double){//被加以double效果
            if(Is_Special(now)){//有特殊牌,直接跑路
                int pos=Special_Decision(now);
                int x=player[now].card[pos];
                if(x==-123){
                    printf("%s used ",player[now].name);
                    Print_Card(x);
                    printf(",now p=%d.\n",P);
                    player[now].card[pos]=deck[++dtot];//摸牌
                    continue;
                }
                if(x==-124){
                    printf("%s used ",player[now].name);
                    Print_Card(x);
                    printf(",now p=%d.\n",P);
                    dir=-dir;
                    player[now].card[pos]=deck[++dtot];
                    continue;
                }
                if(x==-125){
                    printf("%s used ",player[now].name);
                    Print_Card(x);
                    printf(",now p=%d.\n",P);
                    Is_double=1;
                    player[now].card[pos]=deck[++dtot];
                    continue;
                }
            }
            else{//打普通牌
                int pos=Smallest_Decision(P,now);
                int x=player[now].card[pos];
                P=Update_P(P,x);
                printf("%s used ",player[now].name);
                Print_Card(x);
                printf(",now p=%d.\n",P);
                player[now].card[pos]=deck[++dtot];
                Is_double=0;//效果解除
                again=now;//再来一次
            }
        }
        else{//正常
            if(Is_Normal(now)&&!Maybe_Lost(P,now)){//有普通牌
                int pos=Biggest_Decision(P,now);
                int x=player[now].card[pos];
                P=Update_P(P,x);
                printf("%s used ",player[now].name);
                Print_Card(x);
                printf(",now p=%d.\n",P);
                player[now].card[pos]=deck[++dtot];//摸牌
            }
            else{//没普通牌,用特殊牌
                int pos=Special_Decision(now);
                int x=player[now].card[pos];
                if(x==-123){
                    printf("%s used ",player[now].name);
                    Print_Card(x);
                    printf(",now p=%d.\n",P);
                    player[now].card[pos]=deck[++dtot];
                    continue;
                }
                if(x==-124){
                    printf("%s used ",player[now].name);
                    Print_Card(x);
                    printf(",now p=%d.\n",P);
                    dir=-dir;
                    player[now].card[pos]=deck[++dtot];
                    continue;
                }
                if(x==-125){
                    printf("%s used ",player[now].name);
                    Print_Card(x);
                    printf(",now p=%d.\n",P);
                    Is_double=1;
                    player[now].card[pos]=deck[++dtot];
                    continue;
                }
            }
        }
    }
    for(int i=1;i<=3;i++){//输家摸牌
        player[now].card[i]=deck[++dtot];
    }
}
int main(){
    n=read();m=read();k=read();
    Before_Game();//初始化
    while(m--) Round_Start();//游戏开始!
    return 0;
}
查看代码

对拍用造数据:

#include <bits/stdc++.h>
using namespace std;
void Print_Card(int x){
    switch(x){
        case 1:printf("A1");break;
        case 2:printf("A2");break;
        case 5:printf("A5");break;
        case 9:printf("A9");break;
        case 19:printf("A19");break;
        case 49:printf("A49");break;
        case 99:printf("A99");break;
        case -1:printf("B1");break;
        case -9:printf("B9");break;
        case -19:printf("B19");break;
        case 102:printf("C2");break;
        case 103:printf("D2");break;
        case 100:printf("E0");break;
        case 149:printf("E49");break;
        case 199:printf("E99");break;
        case -123:printf("PASS");break;
        case -124:printf("TURN");break;
        case -125:printf("DOUBLE");break;
        default:printf("ERORR");break;
    }
}
int Rand(){
    int x=rand()%18;
    switch(x){
        case 0:return 1;break;
        case 1:return 2;break;
        case 2:return 5;break;
        case 3:return 9;break;
        case 4:return 19;break;
        case 5:return 49;break;
        case 6:return 99;break;
        case 7:return -1;break;
        case 8:return -9;break;
        case 9:return -19;break;
        case 10:return 102;break;
        case 11:return 103;break;
        case 12:return 100;break;
        case 13:return 149;break;
        case 14:return 199;break;
        case 15:return -123;break;
        case 16:return -124;break;
        case 17:return -125;break;
    }
}
int getint(int n){
    int x=rand()%n+1;
    return x;
}
int main(){
    freopen("a+b.in","w",stdout);
    srand(time(0));
    int n=3,m=getint(5),k=500;
    printf("%d %d %d",n,m,k);
    printf("\nXiaoMing ");
    for(int i=1;i<=3;i++){
        int x=Rand();
        Print_Card(x);printf(" ");
    }
    printf("\nXiaoHong ");
    for(int i=1;i<=3;i++){
        int x=Rand();
        Print_Card(x);printf(" ");
    }
    printf("\nLiHua ");
    for(int i=1;i<=3;i++){
        int x=Rand();
        Print_Card(x);printf(" ");
    }
    printf("\n");
    for(int i=1;i<=k;i++){
        int x=Rand();
        Print_Card(x);printf(" ");
    }
}
View Code

 

posted @ 2022-04-09 10:38  blue_tsg  阅读(183)  评论(2编辑  收藏  举报