【BZOJ 1647】[Usaco2007 Open]Fliptile 翻格子游戏 模拟、搜索

第一步我们发现对于每一个格子,我们只有翻和不翻两种状态,我们发现一旦确定了第一行操作,那么第二行的操作也就随之确定了,因为第一行操作之后我们要想得到答案就得把第一行全部为0,那么第二行的每一个格子的操作都会对应于其上的格子的改变,而且也只有第二行能救他了。因此我们只要知道第一行的操作其他的就全都可以推知了,于是我们就用状压枚举第一行的操作,因为这是天然字典序。

#include <cstdio>
#include <iostream>
using namespace std;
int A[20],n,m,a[20],full,b[20],ANS[20],god,Ans=0x7fffffff;
int main(){
  scanf("%d%d",&m,&n);
  full=(1<<n)-1;
  for(register int i=1,x;i<=m;i++){
    for(register int j=1;j<=n;j++)
      scanf("%d",&x),a[i]|=(x<<(n-j));
  }
  if(n==1)
  {
    b[1]=1;
  }
  else
  {
    b[1]=3;
    for(register int i=2;i<n;i++)
     b[i]=(1<<i)|(1<<(i-1))|(1<<(i-2));
    b[n]=(1<<(n-1))|(1<<(n-2));
  }
  for(register int k=0;k<=full;k++)
  {
    register int now=a[1],p=k,sum=0;
    A[1]=k;
    for(register int i=1;i<=n;i++)
      if(k&(1<<(i-1)))now^=b[i],sum++;
    p=now;
    for(register int i=2;i<=m;i++)
    {
      now=a[i];
      A[i]=p;
      for(register int j=1;j<=n;j++)
        if(A[i-1]&(1<<(j-1)))now^=(1<<(j-1));
      for(register int j=1;j<=n;j++)
        if(p&(1<<(j-1)))now^=b[j],sum++;
      p=now;
    }
    if(!p)
    {
      god=1;
      if(sum<Ans)
      {
        for(register int i=1;i<=m;i++)ANS[i]=A[i];
        Ans=sum;
      }
    }
  }
  if(god)
  {
    for(int i=1;i<=m;i++)
    {
      for(int j=n;j>0;j--)
      {
        if(ANS[i]&(1<<(j-1)))
          printf("1 ");
        else
          printf("0 ");
      }
      puts("");
    }
    return 0;
  }
  printf("IMPOSSIBLE");
}

 

posted @ 2017-08-05 08:33  TS_Hugh  阅读(218)  评论(0编辑  收藏  举报