CCF CSP认证 201803-4 棋局评估 (dp/α-β剪枝) (100分)
经典的双人非对称零和博弈,对于Alice来说,肯定取后继状态中得分最高的一个,对于Bob来说,肯定取得分最低的一个,记忆化搜索即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,inf=0x3f3f3f3f,mod=998244353; 5 unordered_map<ll,int> dp; 6 int a[4][4],p[4][4]; 7 ll enc() { 8 ll S=0; 9 for(int i=1; i<=3; ++i) 10 for(int j=1; j<=3; ++j) 11 S|=(ll)a[i][j]<<p[i][j]; 12 return S; 13 } 14 bool win(int f) { 15 for(int i=1; i<=3; ++i) { 16 if(a[i][1]==f&&a[i][2]==f&&a[i][3]==f)return 1; 17 if(a[1][i]==f&&a[2][i]==f&&a[3][i]==f)return 1; 18 } 19 if(a[1][1]==f&&a[2][2]==f&&a[3][3]==f)return 1; 20 if(a[1][3]==f&&a[2][2]==f&&a[3][1]==f)return 1; 21 return 0; 22 } 23 int cnt() { 24 int ret=0; 25 for(int i=1; i<=3; ++i) 26 for(int j=1; j<=3; ++j) 27 if(!a[i][j])ret++; 28 return ret; 29 } 30 int dfs(ll S,int f) { 31 if(dp.count(S))return dp[S]; 32 int& ret=dp[S]; 33 if(win(1))return ret=cnt()+1; 34 if(win(2))return ret=-(cnt()+1); 35 if(cnt()==0)return ret=0; 36 ret=f==1?~inf:inf; 37 for(int i=1; i<=3; ++i) 38 for(int j=1; j<=3; ++j) 39 if(!a[i][j]) { 40 a[i][j]=f; 41 if(f==1)ret=max(ret,dfs(S|(f<<p[i][j]),f^3)); 42 else if(f==2)ret=min(ret,dfs(S|(f<<p[i][j]),f^3)); 43 a[i][j]=0; 44 } 45 return ret; 46 } 47 48 int main() { 49 for(int i=1,now=0; i<=3; ++i) 50 for(int j=1; j<=3; ++j) 51 p[i][j]=now,now+=2; 52 int _; 53 for(scanf("%d",&_); _--;) { 54 for(int i=1; i<=3; ++i) 55 for(int j=1; j<=3; ++j) 56 scanf("%d",&a[i][j]); 57 printf("%d\n",dfs(enc(),cnt()&1?1:2)); 58 } 59 return 0; 60 }
也可以使用α-β剪枝,无需记忆化搜索:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,inf=0x3f3f3f3f,mod=998244353; 5 int a[4][4]; 6 bool win(int f) { 7 for(int i=1; i<=3; ++i) { 8 if(a[i][1]==f&&a[i][2]==f&&a[i][3]==f)return 1; 9 if(a[1][i]==f&&a[2][i]==f&&a[3][i]==f)return 1; 10 } 11 if(a[1][1]==f&&a[2][2]==f&&a[3][3]==f)return 1; 12 if(a[1][3]==f&&a[2][2]==f&&a[3][1]==f)return 1; 13 return 0; 14 } 15 int cnt() { 16 int ret=0; 17 for(int i=1; i<=3; ++i) 18 for(int j=1; j<=3; ++j) 19 if(!a[i][j])ret++; 20 return ret; 21 } 22 int dfs(int f,int alpha,int beta) { 23 if(win(1))return cnt()+1; 24 if(win(2))return -(cnt()+1); 25 if(cnt()==0)return 0; 26 for(int i=1; i<=3; ++i) 27 for(int j=1; j<=3; ++j) 28 if(!a[i][j]) { 29 a[i][j]=f; 30 int t=dfs(f^3,alpha,beta); 31 if(f==1)alpha=max(alpha,t); 32 else if(f==2)beta=min(beta,t); 33 a[i][j]=0; 34 if(beta<=alpha)break; 35 } 36 return f==1?alpha:beta; 37 } 38 39 int main() { 40 int _; 41 for(scanf("%d",&_); _--;) { 42 for(int i=1; i<=3; ++i) 43 for(int j=1; j<=3; ++j) 44 scanf("%d",&a[i][j]); 45 int f=cnt()&1?1:2; 46 int ans=f==1?dfs(f,~inf,inf):dfs(f,inf,~inf); 47 printf("%d\n",ans); 48 } 49 return 0; 50 }