Fliptile奶牛踩瓷砖 (状态压缩,开关问题,枚举)

题目:Fliptile

题意:

给定一个M*N矩阵,有些是黑色(1表示)否则白色(0表示),每翻转一个(i,j),会使得它和它周围4个格变为另一个颜色,要求翻转最少的点,使得变为全白色的矩阵,输出这个标记了翻转点的矩阵,如果有多个最优解,输出逆字典序最小的那个矩阵,若没有解,输出IMPOSSIBLE。

题解:

参考:Fliptile POJ3279 二进制压缩枚举 解题报告

只要第一行的方案确定,后面的踩发就能确定,所以状压枚举第一行的方案

代码:

/***********************************************/
int ans[30][30];
int a[34][34];
int b[33][33];
int m,n;
int ANS=inf;
ll daan=-1;

int fanzhuan1(ll Y)
{
    mem0(ans);
    int pp=0;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++) a[i][j]=b[i][j];
    for(int i=0;i<n;i++)
    {
        if(Y&(1ll<<i)) //翻转第一行第n-i个
        {
            pp++;
            ans[1][n-i]=1;
            a[1][n-i]=a[1][n-i]?0:1;
            if(i>0) a[1][n-i+1]=a[1][n-i+1]?0:1;
            if(i<n-1) a[1][n-i-1]=a[1][n-i-1]?0:1;
            if(n>1) a[2][n-i]=a[2][n-i]?0:1;
        }
    }

    return pp;
}

void solve(int pp,ll p1)
{

    for(int i=1;i<m;i++)
    {
        for(int j=n;j>=1;j--)
        {
            if(a[i][j])
            {
                ans[i+1][j]=1;
                a[i][j]=0;
                a[i+1][j]=a[i+1][j]?0:1;
                if(j>1) a[i+1][j-1]=a[i+1][j-1]?0:1;
                if(j<n) a[i+1][j+1]=a[i+1][j+1]?0:1;
                if(i+2<=m) a[i+2][j]=a[i+2][j]?0:1;
            }
        }
    }
    for(int j=1;j<=n;j++)
    {
        if(a[m][j]){
            //cout<<"IMPOSSIBLE"<<endl;
            return ;
        }
    }
    ///取最优
    int sum=pp;
    for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    {
        if(ans[i][j]) sum++;
    }
    if(sum<ANS)
    {
        ANS=sum;
        daan=p1;
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    cin>>m>>n;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++) cin>>b[i][j];

    int Y=(1<<n)-1;
    for(ll i=0;i<=Y;i++)
    {
        int t=fanzhuan1(i);
        //cout<<t<<endl;
        solve(t,i);
    }
    if(daan==-1) cout<<"IMPOSSIBLE"<<endl;
    else
    {
        //cout<<daan<<endl;
        int t=fanzhuan1(daan);
        solve(t,daan);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<n;j++) cout<<ans[i][j]<<" ";
            cout<<ans[i][n]<<endl;
        }
    }

    return 0;
}

  

原文地址:https://www.cnblogs.com/liuyongliu/p/10447698.html

时间: 2024-10-05 22:58:26

Fliptile奶牛踩瓷砖 (状态压缩,开关问题,枚举)的相关文章

Fliptile POJ - 3279(状态压缩)

题意:给你一个n * m的矩阵,元素为0/1, 求把所有的元素变成0所需要的最少操作.(每对一个格子操作,该十字格的元素反转) 分析:一看数据量 <= 15, 就有点状态压缩的感jio.从小到大枚举第一行的操作,因为第一行的操作决定了后面所有的操作,所以最后判断对于第一行的操作是不是符合题意即可. 代码: 1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <

poj 1753 Flip Game(bfs状态压缩 或 dfs枚举)

Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each round you f

UVA 1252-Twenty Questions(状态压缩DP+子集枚举)

题目大意:有n个物品,每个物品有m个特征,每个物品的每个特征都可能有或没有,现在假定某个物品,通过询问某些特征来确定这个物品,问最多需要多少次就可以确定物品. 每次询问之后可能根据答案不同来采取不同的进一步询问的策略. 用d[S][S0]表示目前询问了S,得到的回答是S0(即那个物品在S中有S0这些特征),最少还需询问多少次.枚举下一次询问的特征完成递推.最终d[0][0]就是答案.S0显然是S的一个子集.下一次询问的特征不是S已有的特征.如果对于某个d[S][S0]只有一个物品满足,那么此时值

SRM 513 2 1000CutTheNumbers(状态压缩)

SRM 513 2 1000CutTheNumbers Problem Statement Manao has a board filled with digits represented as String[] board. The j-th character of the i-th element of board represents the digit written in cell in row i, column j of the board. The rows are numbe

状态压缩+枚举 POJ 3279 Fliptile

题目传送门 1 /* 2 题意:问最少翻转几次使得棋子都变白,输出翻转的位置 3 状态压缩+枚举:和之前UVA_11464差不多,枚举第一行,可以从上一行的状态知道当前是否必须翻转 4 */ 5 #include <cstdio> 6 #include <cstring> 7 #include <algorithm> 8 using namespace std; 9 10 const int MAXN = 20; 11 const int INF = 0x3f3f3f3

P1052 过河(状态压缩)

P1052 过河(状态压缩) 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,--,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥. 题目给出

算法练习系列—hiho1048 状态压缩一(铺地砖)

题目地址:http://hihocoder.com/problemset/problem/1048 编程之美的课后题也有一个和整个题目一样的.(P269) 题目 这个题目的题意很容易理解,在一个N*M的格子里,我们现在有两种类型的砖块,1 * 2和 2 * 1,问一共有多少种方案,可以将整个N*M的空间都填满. 最简单的例子就是下面的了: 编程之美中题目: 某年夏天,位于希格玛大厦四层的微软亚洲研究院对办公楼的天井进行了一次大规模的装修.原来的地板铺有 N×M 块正方形瓷砖,这些瓷砖都已经破损老

NOIP2005过河[DP 状态压缩]

题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度).坐标为0的点表示桥的起点,坐标为L的点表示桥的终点.青蛙从桥的起点开始,不停的向终点方向跳跃.一次跳跃的距离是S到T之间的任意正整数(包括S,T).当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥. 题目给出独木桥的长度L,青蛙跳跃的距离

POJ 3254. Corn Fields 状态压缩DP (入门级)

Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9806   Accepted: 5185 Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yumm