• BZOJ 1647: [Usaco2007 Open]Fliptile 翻格子游戏


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1647

    解:记得这道题在我初二的时候,老师给过一道差不多的题,唯一区别在于,那道题是打枪影响五个,这道题是翻瓦片。

    唔,首先这道题是一个搜索,我们发现我们先确定了第一行哪些要翻,哪些不要翻,之后,第一行的状态就确定了,如果我们还想把第一行上的黑瓦片翻成白瓦片的话,就需要在下一行当前黑瓦片的正下方打一枪,而且必须在那里打,所以我们只要枚举第一行哪些要翻哪些不要翻,接下来的翻的次数就可以确定了。如果,翻完后,最后一行全为白瓦片就可以拿去更新答案了。至于字典序的问题,我是从0枚举到1的,所以越早得到的答案,字典序越优。

    复杂度:O((2^n)*n*m)(我也没仔细计算过)

    具体的话看一下程序吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #define INF 2100000000
    using namespace std;
    int n,m,ans1,tot[20][20],h[5]={0,-1,1,0,0},l[5]={0,0,0,-1,1},a[20][20];
    int ans2[20][20],s[20],b[20][20];
    bool check(int x,int y)
    {
      if ((x<=0)||(x>m)||(y>n)||(y<=0)) return false;
      return true;
    }
    void dfs(int x)
    {
      if (x==n+1)
    //如果第一行的翻与不翻的状态已经确定下来了,就进行所需次数的统计
      {
          for (int i=1;i<=m;i++)
           for (int j=1;j<=n;j++)
           a[i][j]=b[i][j];
          int sum=0; 
          for (int i=1;i<=n;i++)
          if (s[i]==1) 
          {
            tot[1][i]=1;
            for (int j=0;j<=4;j++)
            if (check(1+h[j],i+l[j])) a[1+h[j]][i+l[j]]=a[1+h[j]][i+l[j]]^1;
    //改变为相反的状态
            sum++;
        }
        else tot[1][i]=0;
        for (int i=2;i<=m;i++)
        for (int j=1;j<=n;j++)
        if (a[i-1][j]==1)
    //由上一行来决定这一行是否要翻
        {
          tot[i][j]=1;
          for (int k=0;k<=4;k++)
          if (check(i+h[k],j+l[k])) a[i+h[k]][j+l[k]]=a[i+h[k]][j+l[k]]^1;
            sum++; 
        }
        else tot[i][j]=0;
        for (int i=1;i<=n;i++)if (a[m][i]==1) return ;
    //如果最后一行还有黑瓦片,那么这种方案是不合法的,直接退出
    //更新答案
        if (sum<ans1) 
        {
          ans1=sum;
          for (int i=1;i<=m;i++)
           for (int j=1;j<=n;j++)
           ans2[i][j]=tot[i][j];
        }
        return;
      }
      else for (int i=0;i<2;i++) 
      {
        s[x]=i;
    //枚举状态
        dfs(x+1);
      }
    }
    int main()
    {
      scanf("%d%d",&m,&n); getchar();
      ans1=INF;
      for (int i=1;i<=m;i++)
       for (int j=1;j<=n;j++)
        scanf("%d",&b[i][j]);
      dfs(1);
      if (ans1!=INF)
      {
      for (int i=1;i<=m;i++)
       for (int j=1;j<=n;j++)
       {
            printf("%d",ans2[i][j]);
            if (j==n) putchar('
    ');
            else putchar(' ');
       }
      }
      else printf("IMPOSSIBLE
    ");
      return 0;
    }
  • 相关阅读:
    p1373【奶牛的卧室】
    p1248【交错匹配】(DP)
    QBXT模拟赛T3
    NOIP冲刺班的考试总结
    欧拉回路的一些东西
    一道dp题目
    Blocks
    玩具取名
    Y的积木
    游荡的奶牛
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6660465.html
Copyright © 2020-2023  润新知