数学&搜索:博弈论之极大极小搜索与alpha-beta减枝
目的是寻找最优的方案使得自己能够利益最大化。
基本思想就是假设自己(A)足够聪明,总是能选择最有利于自己的方案,而对手(B)同样足够聪明,总会选择最不利A的方案
对抗搜索就是对于先手来说,取后手中状态最大的;对于后手来说,取终态中状态最小的
对于第一个人
它一定从当前局面可以到达的所有局面中,选择一个最大的走
第二个人一定会从当前局面所有可以到达的局面中,选择一个最小的走
省选第一题一双木棋
正解是博弈论记忆化搜索+状态压缩
然而我这里先贴一份纯对抗搜索的代码
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 bool vis[12][12]; 5 int a[12][12],b[12][12]; 6 int col[12][12]; 7 int n,m; 8 struct node{ 9 int ans1,ans2; 10 }; 11 node dfs(int num,int f) 12 { 13 if(num==n*m) 14 { 15 int ans1=0,ans2=0; 16 for(int i=1;i<=n;i++) 17 for(int j=1;j<=m;j++) 18 { 19 if(col[i][j]==1) ans1+=a[i][j]; 20 if(col[i][j]==2) ans2+=b[i][j]; 21 } 22 return (node){ans1,ans2}; 23 } 24 node ans; 25 int maxi=-1e9+7; 26 for(int i=1;i<=n;i++) 27 for(int j=1;j<=m;j++) 28 { 29 if(vis[i-1][j]||(i-1==0)) 30 if(vis[i][j-1]||(j-1==0)) 31 if(!vis[i][j]) 32 { 33 vis[i][j]=1; 34 col[i][j]=f; 35 node dx=dfs(num+1,f==1?2:1); 36 vis[i][j]=0; 37 col[i][j]=0; 38 int ansx=f==1?dx.ans1-dx.ans2:dx.ans2-dx.ans1; 39 if(ansx>maxi) maxi=ansx,ans=dx; 40 } 41 } 42 return ans; 43 } 44 int main() 45 { 46 //freopen("chess.in","r",stdin); 47 //freopen("chess.out","w",stdout); 48 scanf("%d%d",&n,&m); 49 for(int i=1;i<=n;i++) 50 for(int j=1;j<=m;j++) 51 scanf("%d",&a[i][j]); 52 for(int i=1;i<=n;i++) 53 for(int j=1;j<=m;j++) 54 scanf("%d",&b[i][j]); 55 node ans=dfs(0,1); 56 printf("%d\n",ans.ans1-ans.ans2); 57 return 0; 58 }
然后是状态压缩+记忆化
1 #include <cstdio> 2 #include <algorithm> 3 #include <map> 4 #define ll long long 5 #define inf 0x7fffffff 6 std::map <ll,int> mp; 7 ll end; 8 int n,m; 9 int num[20],a[20][20],b[20][20]; 10 inline int unzip(ll sta) 11 { 12 int s=0; 13 for(int i=n;i;i--) s+=(num[i]=(sta%(m+1))),sta/=(m+1); 14 return s&1; 15 } 16 inline ll zip() 17 { 18 ll s=0; 19 for(int i=1;i<=n;i++) s=s*(m+1)+num[i]; 20 return s; 21 } 22 int DFS(ll sta) 23 { 24 if(mp.find(sta)!=mp.end()) return mp[sta]; 25 if(sta==end) return 0; 26 int opt=unzip(sta); 27 int ans=opt?inf:-inf; 28 if(num[1]<m) 29 { 30 ++num[1]; 31 if(opt) ans=std::min(ans,DFS(zip())-b[1][num[1]]); 32 else ans=std::max(ans,DFS(zip())+a[1][num[1]]); 33 --num[1]; 34 } 35 for(int i=2;i<=n;i++) 36 if(num[i-1]>num[i]) 37 { 38 ++num[i]; 39 if(opt) ans=std::min(ans,DFS(zip())-b[i][num[i]]); 40 else ans=std::max(ans,DFS(zip())+a[i][num[i]]); 41 --num[i]; 42 } 43 return mp[sta]=ans; 44 } 45 int main() 46 { 47 scanf("%d%d",&n,&m); 48 for(int i=1;i<=n;i++) 49 for(int j=1;j<=m;j++) 50 scanf("%d",&a[i][j]); 51 for(int i=1;i<=n;i++) 52 for(int j=1;j<=m;j++) 53 scanf("%d",&b[i][j]); 54 for(int i=1;i<=n;i++) num[i]=m; 55 end=zip(); 56 DFS(0); 57 printf("%d\n",mp[0]); 58 return 0; 59 }