关闭

[kuangbin带你飞]专题一 简单搜索D - Fliptile(POJ 3279)

标签: kuangbin搜索pojdfsFliptile
1341人阅读 评论(1) 收藏 举报
分类:
题目大意
给一个N行M列的矩阵,值分别为0和1,每次你可以选择将一个变成相反状态,同时,它周围的四个数也会变为相反状态。
问:最少翻转多少次,可以将所有值都变成0
多个解,输出翻转次数最少的(若有次数相同解,输出字典序小的)
若无解,输出”IMPOSSIBLE”
思路
对于每个点,只能有两种操作,翻或不翻,若暴力所有可能性,需要2^(M*N)次操作,显然不可行
所以有了这个法子。
先枚举第一行的所有可能性(2^M),搜索或位运算均可
然后,对坐标(i, j)来说,如果(i-1, j)不为0,那么(i, j)必然需要翻转。
重复进行上操作由2至N
此时,最后一行也已翻转完毕,如果最后一行全为0,得出结果
第一行的所有结果中取最小值
代码
下面是两种方法,思路相同,仅仅是实现细节上略有不同。

1 . dfs搜索

#include <stdio.h>
#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>
#include <queue>
#include <string.h>

using namespace std;

int g[17][17];         //保存初始状态 
int f[17][17] = {};
int ans[17][17] = {};
int mmin = 0x1f1ffff;

bool judge(int n,int m)//判断最后一行是否全为0
{
    for(int i=1;i<=m;i++)
    {
        int t = f[n][i]+f[n][i-1]+f[n][i+1]+f[n-1][i];
        if((g[n][i]+t)&1)
            return false;
        }
    return true;
}

void dfs(int n,int m,int k,int num)
{
    if(num > mmin)//剪枝
        return;
    if(k > n)
    {
        if(judge(n, m) && mmin>num)//判断是否符合条件
        {
            memcpy(ans, f, sizeof(f));
            mmin = num;
        }
        return;
    }
    int t = 0;
    for(int i=1;i<=m;i++)
    {
        if((g[k-1][i]+f[k-2][i]+f[k-1][i-1]+f[k-1][i+1]+f[k-1][i])&1)//上一行是否为1,即是否需要翻转
        {
            f[k][i] = 1;
            t++;
        }
        else
            f[k][i] = 0;
    }
    dfs(n, m, k+1, num+t);
}

//n,m行列数   k当前列  num第一行翻转的次数
void todfs(int n, int m, int k, int num)
{
    if(k > m)
    {
        dfs(n, m, 2, num); //对第一行每种情况进行搜索
        return;
    }
    f[1][k] = 0;      //不翻转
    todfs(n, m, k+1, num);
    f[1][k] = 1;      //翻转,num+1
    todfs(n, m, k+1, num+1);
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)//下标从1开始,便于边界处理
            cin>>g[i][j];
    todfs(n, m, 1, 0);     //递归遍历第一行所有情况
    if(mmin == 0x1f1ffff)
        cout<<"IMPOSSIBLE"<<endl;
    else
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cout<<ans[i][j]<<" ";
            cout<<endl;
        }
    return 0;
}

2 . 枚举递推

#include <stdio.h>
#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>
#include <queue>
#include <string.h>

using namespace std;

int g[17][17];         //保存初始状态 
int f[17][17] = {};
int ans[17][17] = {};
int mmin = 0x1f1ffff;

bool judge(int n,int m)//判断最后一行是否全为0
{
    for(int i=1;i<=m;i++)
    {
        int t = f[n][i]+f[n][i-1]+f[n][i+1]+f[n-1][i];
        if((g[n][i]+t)&1)
            return false;
    }
    return true;
}

void fun(int n, int m, int num)
{
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(num > mmin)
                return;
            if((g[i-1][j]+f[i-2][j]+f[i-1][j-1]+f[i-1][j+1]+f[i-1][j])&1)//上一行是否为1,即是否需要翻转
            {
                f[i][j] = 1;
                ++num;

            }
            else
                f[i][j] = 0;
        }
    }
    if(judge(n, m) && mmin>num)//判断是否符合条件
    {
        memcpy(ans, f, sizeof(f));
        mmin = num;
    }
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)//下标从1开始,便于边界处理
            cin>>g[i][j];
    for(int i=0;i < 1<<(m+1);i++)
    {
        int num = 0;
        for(int j=1;j<=m;j++)
        {
            f[1][j] = i>>(m-j+1) & 1;
            num += f[1][j];
        }
        fun(n, m, num);
    }
    if(mmin == 0x1f1ffff)
        cout<<"IMPOSSIBLE"<<endl;
    else
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cout<<ans[i][j]<<" ";
            cout<<endl;
        }
    return 0;
}
2
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

POJ 3279 Fliptile(反转)

Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6081   Accepted: 2308 ...
  • zwj1452267376
  • zwj1452267376
  • 2016-01-31 22:04
  • 2150

POJ 3279 Fliptile(状态压缩+暴力)

题意: 给出最高15*15的0 1矩阵,每次可以翻转一个点,其相邻的4个点都被翻转,问最少翻转几次可以全部变为0。 解析: 枚举第一行的翻转所有翻转情况然后逐行向下更新,如果上一行是1的话,那...
  • HelloWorld10086
  • HelloWorld10086
  • 2015-05-20 20:20
  • 1949

Fliptile POJ 3279(开关问题)

Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He ha...
  • chat_c
  • chat_c
  • 2016-02-12 00:57
  • 534

暑期第一弹<搜索> D - Fliptile(黑白棋翻转经典题型 DFS)

D - Fliptile Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64...
  • qq_28300479
  • qq_28300479
  • 2016-07-11 17:44
  • 818

[kuangbin带你飞]专题一 简单搜索 -D - Fliptile

Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He ha...
  • sb_Ihateyou
  • sb_Ihateyou
  • 2017-04-14 21:56
  • 2268

Fliptile

题意:m*n个格子,每个格子可以翻转正反面,每次翻转一个格子时,与它上下左右相邻接的格子也会被翻转。给定每个格子的颜色,求出将每个格子变成白色的最小步数,如果有多个解时输出字典序最小的一个解 解题思路...
  • acm_xx
  • acm_xx
  • 2017-10-23 22:35
  • 71

题解:POJ 3279 Fliptile (BFS)

D - Fliptile Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I64d &%I64u D...
  • sun897949163
  • sun897949163
  • 2016-01-25 21:56
  • 751

[kuangbin带你飞]专题一 简单搜索 D - Fliptile poj 3279

D - Fliptile Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u S...
  • qq1319479809
  • qq1319479809
  • 2015-11-12 21:20
  • 181

POJ 3279 Fliptile(状态压缩+暴力)

题意: 给出最高15*15的0 1矩阵,每次可以翻转一个点,其相邻的4个点都被翻转,问最少翻转几次可以全部变为0。 解析: 枚举第一行的翻转所有翻转情况然后逐行向下更新,如果上一行是1的话,那...
  • HelloWorld10086
  • HelloWorld10086
  • 2015-05-20 20:20
  • 1949

POJ 3279 Fliptile(kuangbin带你飞 专题一:简单搜索)

题意:给定一个n*m的矩阵,可以翻转矩阵的某个位置,然后这个位置的上下左右也随之翻转,0成1 1变0这样..问最少需要多少次操作可以吧这个矩阵全部为0,可以的话输出如何操作的... 这个题...一眼看...
  • azx736420641
  • azx736420641
  • 2015-01-28 17:11
  • 409
    ~~~
    欢迎访问我的新博客地址:shiyi.fightcoder.com
    有问题,可以发邮件到 shiyi19960604@qq.com ,不要私信了,以后大概不太登csdn了。
    个人资料
    • 访问:246142次
    • 积分:4204
    • 等级:
    • 排名:第8443名
    • 原创:166篇
    • 转载:8篇
    • 译文:0篇
    • 评论:86条
    博客专栏
    最新评论