当前位置: 代码迷 >> 综合 >> rqnoj-116-质数取石子-dp
  详细解决方案

rqnoj-116-质数取石子-dp

热度:83   发布时间:2023-12-19 11:06:48.0

dp[1][i]: 

DD选择的时候,剩余i石子,DD赢的最小步数。若此时DD是必败态,则为-1;

dp[2][i]:

MM选择的时候,剩余i石子,MM输的最步数。若此时DD是必态,则为-1; 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
#define maxn 20050
int prime[maxn];
int isprime[maxn];
int nearprime[maxn];
int numprime;
int dp[3][maxn];
void dos()
{prime[0]=0;prime[1]=0;prime[2]=1;for(int i=3;i<maxn;i++)prime[i]=i%2;for(int i=2;i<sqrt(maxn);i++){if(prime[i]==0)continue;for(int j=2;j*i<maxn;j++){prime[j*i]=0;}}numprime=0;for(int i=0;i<maxn;i++){if(prime[i])isprime[numprime++]=i;nearprime[i]=numprime-1;}
}
int pan(int people,int n)
{int i;if(dp[people][n]!=-2)return dp[people][n];if(people==1){int leap=0;dp[1][n]=9999999;if(prime[n]||prime[n-1]){dp[1][n]=1;return 1;}for(i=0;i<=nearprime[n];i++){if(pan(2,n-isprime[i])>-1){dp[1][n]=min(dp[1][n],dp[2][n-isprime[i]]+1);leap=1;}}if(leap==0)dp[1][n]=-1;}else if(people==2){dp[2][n]=0;if(prime[n]||prime[n-1]){dp[2][n]=-1;return -1;}for(i=0;i<=nearprime[n];i++){if(pan(1,n-isprime[i])==-1){dp[2][n]=-1;break;}else{dp[2][n]=max(dp[1][n-isprime[i]]+1,dp[2][n]);}}}return dp[people][n];
}
void play()
{dos();int i;for(i=0;i<maxn;i++)dp[1][i]=dp[2][i]=-2;dp[1][0]=-1;dp[1][1]=-1;dp[1][2]=1;dp[2][0]=0;dp[2][1]=0;dp[2][2]=-1;for(i=3;i<maxn;i++){dp[1][i]=pan(1,i);}
}
int main()
{int n,m;play();scanf("%d",&n);while(n--){scanf("%d",&m);printf("%d\n",dp[1][m]);}return 0;
}