P4363 [九省联考2018]一双木棋
这种搜索要把后继状态都跑出来之后取Min/Max
也就是回溯的时候进行操作
记得用hash进行记忆化(用map不开O2会TLE)
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<map> #define rg register #define max(x,y) (x)<(y)?(y):(x) #define min(x,y) (x)>(y)?(y):(x) using namespace std; int n,m,A[11][11],B[11][11],ri[11];//ri[]:每行向右延伸到了多少 map<long long,int>dp; inline int read() { rg int save=0,w=1;rg char q=getchar(); while(q<'0'||q>'9'){if(q=='-')w=-1;q=getchar();} while(q>='0'&&q<='9')save=(save<<3)+(save<<1)+q-'0',q=getchar(); return save*w; } inline long long zip()//算出hash值 { rg long long hash=0; for(rg int i=1;i<=n;++i)hash=(hash<<3)+(hash<<1)+hash+ri[i]; return hash; } inline void recover(rg long long hash)//把状态解析出来 { for(rg int i=n;i>=1;--i)ri[i]=hash%11,hash/=11; } int dfs(rg long long hash,rg bool b)//当前状态为hash,是谁下子(b==1为菲菲,b==0为牛牛) { rg int ans=((!b)?2147483647:-2147483647),i; if(dp[hash])return ((dp[hash]==-1)?0:dp[hash]);//如果该状况已经拓展过了,把记忆化的值返回即可 //且因为A数组与B数组相加减的答案可能为0,而dp[]需要记录答案,所以当答案为0时,赋给dp[]的值为-1 recover(hash); for(i=1;i<=n;++i)//枚举在哪一行向右走 { if(ri[i]<ri[i-1]) { ri[i]++; rg int behind=dfs(zip(),!b);//回溯回来的答案为behind if(b)ans=max(ans,behind+A[i][ri[i]]);//菲菲尽量使差变大 (差:菲菲-牛牛) else ans=min(ans,behind-B[i][ri[i]]);//牛牛尽量使差变小 ri[i]--;//回溯,试着走别的点 } } if(ans==((!b)?2147483647:-2147483647))ans=0; dp[hash]=(!ans)?-1:ans; return ans; } int main() { n=read(),m=read(); rg int i,j; for(i=1;i<=n;++i) for(j=1;j<=m;++j) A[i][j]=read(); for(i=1;i<=n;++i) for(j=1;j<=m;++j) B[i][j]=read(); // Take me to your heart, take me to your soul, give me your hand and hold me. ri[0]=m; printf("%d\n",dfs(0,1)); return 0; }