题意:在一个n*m的棋盘上,A和B轮流放置棋子。一个位置能够放置棋子当且仅当它上面没有棋子并且它的上面和左边一格都已经放了棋子(不难发现是一个上三角阶梯状)。每个格子有两个权值,当A在上面放置棋子时A获得a[i][j]的得分,B同理。
A和B用最优策略,A想要A-B最大,B想要B-A最大(即使A-B最小)。问最后A-B为多少?
标程:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int read() 4 { 5 int x=0,f=1;char ch=getchar(); 6 while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} 7 while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 8 return x*f; 9 } 10 const int inf=0x3f3f3f3f; 11 map<int,int> mp; 12 int n,m,a[12][12],b[12][12],vis[12],w[12][12]; 13 int dfs(int op,int hsh) 14 { 15 if (mp[hsh]) return mp[hsh]; 16 if (vis[n]==m) return 0; 17 int ans=(op==0)?inf:-inf; 18 for (int i=1;i<=n;i++) 19 if (vis[i]!=vis[i-1]&&vis[i]!=m) 20 { 21 vis[i]++; 22 if (op==0) ans=min(ans,dfs(op^1,hsh^w[i][vis[i]])-b[i][vis[i]]); 23 else ans=max(ans,dfs(op^1,hsh^w[i][vis[i]])+a[i][vis[i]]); 24 vis[i]--; 25 } 26 return mp[hsh]=ans; 27 } 28 int main() 29 { 30 srand(time(NULL)); 31 n=read();m=read(); 32 for (int i=1;i<=n;i++) 33 for (int j=1;j<=m;j++) a[i][j]=read(); 34 for (int i=1;i<=n;i++) 35 for (int j=1;j<=m;j++) b[i][j]=read(),w[i][j]=rand(); 36 vis[1]=1; 37 printf("%d\n",a[1][1]+dfs(0,0)); 38 return 0; 39 }
题解:决策性搜索+记忆化
每一行保存扩展到哪里,这个hash成状态S。dfs(S)表示在S补的状态下A-B的值。
A先手,取max(dfs(S')+a[i][j])。B先手,取min(dfs(S')-b[i][j])。
不想写hash写个熟练的随机权值异或一下:)。搜索用map记忆化要习惯。
P.S.自己写的时候dfs表示当前局面的先手-后手的得分,绕来绕去较难写。写程序要写得聪明点。
对于某个状态S,先后手是谁可以通过取格子数唯一确定,不需要压进map。