[九省联考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;
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/8735438.html