1. 程式人生 > 其它 >「Wdsr-2.5」琪露諾的算數遊戲 題解 大模擬

「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