D - Deductive Snooker Scoring

[https://qoj.ac/contest/2567/problem/14709]

题意:

斯诺克台球,给出最后的选手A和选手B的得分,以及最后到谁打了,构造一个合法操作序列使得最后结果为给出结果

思路:

记忆化搜索:f[i][j][lft][k][op] 表示 选手A得分为i,选手B得分为j,剩下的球的总数为lft,到选手k打了,比赛阶段(第一阶段打红球,第二阶段打彩球且放回,第三阶段清台)

发现不需要知道红球多少个,彩球多少个才能知道比赛进行的阶段,因为一定是红球先打完。所以剩下来的球小于等于6个时,一定进入清台阶段

int a,b,n,p;
string f[202][202][22][2][3];

//op:0 1 2
//三个阶段

//A:选手A得分
//B:选手B得分
//lft:当前剩余的球的总数
//k:当前击球的选手
//op:阶段
//s:字符串

void dfs(int A,int B,int lft,int k,int op,string s){
    if(f[A][B][lft][k][op].size())return ; 
    f[A][B][lft][k][op]=s;
    if(!lft)return;

    if(op==0){
        
        if(k==0)dfs(A+1,B,lft-1,k,op+1,s+'1');//选手A进入第二阶段
        else    dfs(A,B+1,lft-1,k,op+1,s+'1');//选手B进入第二阶段
        // dfs(A,B,lft,k^1,op,s+'/');//第一阶段没打进

    }

    if(op==1){

        for(int i=7;i>=2;i--){
            //枚举彩球
            if(k==0)dfs(A+i,B,lft,k,lft>=7?0:2,s+(char)('0'+i));
            else    dfs(A,B+i,lft,k,lft>=7?0:2,s+(char)('0'+i));
        }
        // dfs(A,B,lft,k^1,op-1,s+'/');//第二阶段没打进

    }

    if(op==2){

        if(k==0)dfs(A+8-lft,B,lft-1,k,op,s+(char)('0'+(8-lft)));
        else    dfs(A,B+8-lft,lft-1,k,op,s+(char)('0'+(8-lft)));
        // dfs(A,B,lft,k^1,op,s+'/');

    }
    
    dfs(A,B,lft,k^1,lft>=7?0:2,s+'/');
}

void solve(){
    cin>>a>>b>>n>>p;
    if(a==0&&b==0&&n==21&&p==0){
        cout<<endl;return;
    }
    for(int i=0;i<=2;i++){
        if(f[a][b][n][p][i].size()){
            cout<<f[a][b][n][p][i]<<endl;return;
        }
    }
    cout<<"NA"<<endl;
}

signed main()
{
  ios::sync_with_stdio(false),cin.tie(0);
  int T=1;
cin>>T;
dfs(0,0,21,0,0,"");
  while(T--){
  solve();
  }

  return 0;
}
posted @ 2025-11-10 15:43  Marinaco  阅读(11)  评论(0)    收藏  举报
//雪花飘落效果