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 }

 

posted @ 2020-09-08 11:19  jrltx  阅读(199)  评论(0编辑  收藏  举报