POJ-3279(Fliptile)--简单搜索

题目大意:给你一个01矩阵,可以进行翻转操作(0变1,1变0,而且一定要成十字,边界不管),最后你要将这个矩阵变成全0矩阵,给出操作矩阵

   而且在所有可以的操作矩阵中,找出总操作数最少的,并且字典序最小的。

   (我靠,这题意写得,我自己都未必明白)

解题思路:题目看起来不好做,但是注意以下几点就明白了:

1、若第一行的翻转位置确认,则后面所有位置就可以确认;

2、任何位置最多翻转一次,若同一位置翻转2次,就相当于不翻转。

本题所给的矩阵较小,可以枚举第一行的所有翻转情况,逐次验证,并判断翻转次数,存储翻转次数最小的那种情况。

因为可能有次数相同的情况,那么我从右往左枚举,那么次数相同就取先找到的符合要求的情况,即次数相同不予覆盖。

代码:

#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define PB push_back
#define FOR(i,n,m) for(int i=n;i<=m;i++)
#define ROF(i,n,m) for(int i=n;i>=m;i--)
#define clr(i,j) memset(i,j,sizeof(i))
#define maxn 17
typedef long long ll;
int chess[maxn][maxn];
int temp[maxn][maxn];
int p[maxn][maxn];
int res[maxn][maxn];
int dir[4][2]= {0,1,0,-1,1,0,-1,0};
int m,n;
void flip(int x,int y)
{
    temp[x][y]^=1;
    for(int i=0; i<4; i++)
    {
        int t1=x+dir[i][0],t2=y+dir[i][1];
        if(t1>0&&t1<m+1&&t2>0&&t2<n+1)temp[t1][t2]^=1;
    }
}
int main()
{
    while(~scanf("%d %d",&m,&n))
    {
        for(int i=1; i<=m; i++)
            for(int j=1; j<=n; j++)
                scanf("%d",&chess[i][j]);
        int upper=1<<n;
        int ans=0,minn=0x7fffffff;
        for(int k=0; k<upper; k++)
        {
            int anw=0;
            memcpy(temp,chess,sizeof(chess));
            for(int i=n-1; i>=0; i--)
            {
                p[1][n-i]=(k>>i)&1;
                if(p[1][n-i])
                {
                    flip(1,n-i);
                    anw++;
                }
            }
            for(int i=2; i<=m; i++)
            {
                for(int j=1; j<=n; j++)
                {
                    p[i][j]=temp[i-1][j];
                    if(p[i][j])
                    {
                        flip(i,j);
                        anw++;
                    }
                }
            }
            int flag=1;
            for(int i=1; i<=n; i++)
                if(temp[m][i])
                {
                    flag=0;
                    break;
                }
            if(flag)
            {
                ans=1;
                if(anw<minn)
                {
                    memcpy(res,p,sizeof(p));
                    minn=anw;
                }
            }
        }
        if(ans)
        {
            for(int i=1; i<=m; i++)
            {
                printf("%d",res[i][1]);
                for(int j=2; j<=n; j++)
                    printf(" %d",res[i][j]);
                printf("\n");
            }
        }
        else printf("IMPOSSIBLE\n");
    }
    return 0;
}

你可能感兴趣的:(搜索)