poj 3279(翻转问题贪心)

本文介绍了一种解决二维翻转问题的方法,通过枚举第一行状态进行贪心操作,适用于n和m都小于15的情况。特别处理了n等于1的情况,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


翻转问题一般是从前面开始贪心,如果是一维的话直接从前面往后贪心,如果是二维的话,就得枚举第一行的状态,然后从第一行往下贪心。


这个题就是二维的开关问题,需要枚举第一行的状态,复杂度为2^n,然后往后遍历贪心。总复杂度为2^n * n*m,因为n < 15 && m < 15,所以能在时限内通过。

PS :要特判n == 1,把他当作一维的来做


Code:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 10 + 10;
#define INF 0x3f3f3f3f
int n,m;

int a[maxn][maxn];
int b[maxn][maxn];
void work(int x,int y)
{
    a[x][y] ^= 1;
    a[x - 1][y] ^= 1;
    a[x + 1][y] ^= 1;
    a[x][y - 1] ^= 1;
    a[x][y + 1] ^= 1;
}
int vis[maxn][maxn];
int main()
{
    while( ~ scanf("%d%d",&n,&m))
    {
        memset(vis,0,sizeof(vis));
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            scanf("%d",&b[i][j]);
        if(n == 1 && m == 1)
        {
            if(b[1][1] == 1)
                puts("1");
            else puts("0");
            continue;
        }
        if(n == 1)
        {
            int ans = 0;
            for(int i = 1; i <= n; i ++)
                for(int j = 1; j <= m; j ++)
                a[i][j] = b[i][j];
            for(int j = 1; j < m; j ++)
            {
                if(a[1][j] == 1)
                {
                    work(1,j + 1);
                    ans ++;
                    vis[1][j + 1] = 1;
                }
            }
//            cout << ans << endl;
            bool flags = 1;
            for(int j = 1; j <= m; j ++)
            if(a[1][j] == 1)
            {
                flags = 0;
//                cout << j << endl;
                puts("IMPOSSIBLE");
                break;
            }
            if(flags)
            for(int j = 1; j <= m; j ++)
                printf("%d%c",vis[1][j],j <= m - 1 ? ' ' : '\n');
            continue;
        }
        int ans = INF;
        int temp;
        for(int k = 0; k < (1 << n); k ++)//枚举第一层的翻转顺序
        {
            for(int i = 1; i <= n; i ++)
                for(int j = 1; j <= m; j ++)
                a[i][j] = b[i][j];
            int cnt = 0;
            memset(vis,0,sizeof(vis));
            int temps = 0;
            for(int j = 1; j <= n; j ++)
            {
                if((1 << (j - 1)) & k)
                {
                    work(1,j),vis[1][j] = 1,cnt ++;
                }
            }
            for(int i = 1; i < n; i ++)
            {
                for(int j = 1; j <= m; j ++)
                {
                    if(a[i][j] == 1)
                    {
                        work(i + 1,j);
                        cnt ++;
                        vis[i + 1][j] = 1;
                    }
                }
            }
            for(int j = 1; j <= m; j ++)
            if(a[n][j] == 1)
            {
                cnt = INF;
                break;
            }
//            cout << cnt << " ";
            if(cnt < ans)
                ans = cnt,temp = k;
        }
//        cout << endl;
        if(ans == INF)
        {
            puts("IMPOSSIBLE");
            continue;
        }

        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            a[i][j] = b[i][j];
        memset(vis,0,sizeof(vis));
        for(int j = 1; j <= n; j ++)
        {
            if((1 << (j - 1)) & temp)
                work(1,j),vis[1][j] = 1;
        }
        for(int i = 1; i < n; i ++)
        {
            for(int j = 1; j <= m; j ++)
            {
                if(a[i][j] == 1)
                {
                    work(i + 1,j);
                    vis[i + 1][j] = 1;
                }
            }
        }
        for(int i = 1; i <= n; i ++)
        {
            for(int j = 1; j <= m; j ++)
            {
                printf("%d%c",vis[i][j],j < m ? ' ' : '\n');
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值