「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(" "); } }
This is your dream.Anything you can dream,you can do it now.