[九省联考2018]一双木棋chess
题解:
水题吧
首先很显然的是状压或者搜索
考虑一下能不能状压吧
这个东西一定是长成三角形的样子的
所以是可以状压的
相邻两位之间有几个0代表他们差几
这样最多会有2n
然后就可以转移了
由于之前对博弈dp的理解非常傻逼
刚开始正着dp以为可能是一样的然后就挂了
当然是要,倒着dp才对。。
代码:
#include <bits/stdc++.h> using namespace std; #define INF 1e9 int dp[1<<21],dp2[1<<21],a1[12][12],b1[12][12]; int n,m,f[12]; void maxa(int &a,int b) { a=max(a,b); } int cl(int x,int y1) { int l=0,l1=0,tmp=x,y=y1-1; while (y) { if (x%2==1) y--; x/=2; l++; } tmp=tmp-(x<<l); x>>=1; if (y1!=n) { while (x%2==0) l1++,x/=2; x=(x-1)<<1; x+=1; x<<=l1; } x<<=l; return(tmp+x); } int main() { freopen("noip.in","r",stdin); freopen("noip.out","w",stdout); std::ios::sync_with_stdio(false); cin>>n>>m; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) cin>>a1[i][j]; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) cin>>b1[i][j]; for (int j=0;j<1<<21;j++) dp[j]=-INF; int maxn=(1<<n)-1; maxn<<=m; /*if (n*m%2==0) dp[maxn]=b1[n][m]; else dp[maxn]=a1[n][m];*/ dp[maxn]=0; for (int k=2;k<=n*m;k++) { for (int j=0;j<1<<21;j++) dp2[j]=-INF; for (int i=1;i<=maxn;i++) if (dp[i]!=-INF) { int l=0,x=i,tmp; for (int j=1;j<=n;j++) { while (x%2==0) x/=2,l++; f[j]=l; x/=2; } tmp=((n*m-k)%2+3)%2; x=i; for (int j=n;j;j--) { if (f[j]>f[j-1]) { int y=cl(x,j); if (tmp==0) maxa(dp2[y],-dp[i]+a1[n-j+1][f[j]]); if (tmp==1) maxa(dp2[y],-dp[i]+b1[n-j+1][f[j]]); } } } memcpy(dp,dp2,sizeof(dp2)); } maxn=(1<<(n-1))-1; maxn+=1<<n; cout<<-dp[maxn]+a1[1][1]; return 0; }