zoukankan      html  css  js  c++  java
  • POJ 3279 Fliptile[二进制状压DP]

    题目链接【http://poj.org/problem?id=3279】

    题意:给出一个大小为M*N(1 ≤ M ≤ 15; 1 ≤ N ≤ 15) 的图,图中每个格子代表一个灯泡,mp[i][j] = 0;表示(i,j)这盏灯灭,反之则亮。如果把反转(i,j)等的开关,那么这个灯和他上下左右的等都会变成原来相反的的状态。

    问:用最少的使用开关的次数使得灯全部被熄灭。

    思路:用0,1表示第一行每个位置是否使用开关,所有状态最多有(1<<15)-1种,如果第一行的状态确定了,其他行的开关状态也就确定了。即:当第一行开关反转过后,那么如果第一行(i,j)灯为0,呢么下一行(i+1,j)灯的开关就不能反转,反之必须反转,只有这样,当前行的灯才能被全灭。所以,枚举第一行的所有状态,逐层向下模拟,最后判断最后一行是否被全灭即可,同时维护最小值的状态即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int INF = 1e5;
    const int maxn = 1 << 16;
    int mp[17][17];
    int t[17][17];
    int ans[17][17];
    int n, m;
    int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
    bool check()
    {
        for(int j = 1; j <= m; j++)
            if(t[n][j])    return 0;
        return 1;
    }
    void init()
    {
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                t[i][j] = mp[i][j];
    }
    int flip(int x, int y)
    {
        t[x][y] ^= 1;
        for(int i = 0; i <= 3; i++)
        {
            int X = x + dir[i][0];
            int Y = y + dir[i][1];
            if(X >= 1 && X <= n && Y >= 1 && Y <= m)
                t[X][Y] ^= 1;
        }
    }
    int tap(int k)
    {
        init();
        int num = 0;
        //处理第一行
        for(int i = 1; k; i++)
        {
            if(k & 1)
                flip(1, i), num++;
            k >>= 1;
        }
        //处理后面的行数
        for(int i = 1; i < n; i++)
            for(int j = 1; j <= m; j++)
            {
                if(t[i][j])
                    flip(i + 1, j), num++;
            }
        return num;
    }
    void tap2(int k)
    {
        init();
        memset(ans, 0, sizeof(ans));
        for(int i = 1; k; i++)//第一行
        {
            if(k & 1)
                flip(1, i), ans[1][i] = 1;
            k >>= 1;
        }
        for(int i = 1; i < n; i++)
            for(int j = 1; j <= m; j++)
            {
                if(t[i][j])
                    flip(i + 1, j), ans[i + 1][j] = 1;
            }
    }
    int main ()
    {
        while(~scanf("%d%d", &n, &m))
        {
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= m; j++)
                    scanf("%d", &mp[i][j]);
            int mask = (1 << m) - 1;
            int T = INF;
            for(int i = 0; i <= mask; i++)
            {
                int num = tap(i);//反转
                if(check() && num < T)
                {
                    T = num;
                    tap2(i);//记录反转
                }
            }
            if(T == INF)
                printf("IMPOSSIBLE
    ");
            else
            {
                for(int i = 1; i <= n; i++)
                {
                    for(int j = 1; j < m; j++)
                        printf("%d ", ans[i][j]);
                    printf("%d
    ", ans[i][m]);
                }
            }
        }
        return 0;
    }
    想的太多,做的太少。
  • 相关阅读:
    web前端图片上传
    二级联动
    前端框架
    获取URL域名
    监听横屏竖屏
    下载中间件、爬虫中间件
    起始url的调度原理
    自定义代理IP
    爬虫深度控制
    手动处理cookie(实现一个点赞爬虫)
  • 原文地址:https://www.cnblogs.com/pealicx/p/6232313.html
Copyright © 2011-2022 走看看