4.翻转(简单搜索 枚举)
翻转
↑ 题目链接
题目
给定一个 \(M×N\) 的 \(01\) 矩阵。
你需要选择其中一些元素,并对选择的元素进行翻转操作。
翻转操作是指将所选元素以及与其上下左右相邻的元素(如果有)进行翻转(0 变 1,1 变 0)。
我们希望最终矩阵变为一个全 \(0\) 矩阵,并且选择进行翻转操作的元素数量尽可能少。
输出最佳翻转方案。
输入格式
第一行包含整数 \(M,N\)。接下来 \(M\) 行,每行包含 \(N\) 个整数,每个整数为 \(0\) 或 \(1\)
输出格式
共 \(M\) 行,每行包含 \(N\) 个整数,其中第 \(i\) 行第 \(j\) 列的整数,表示第 \(i\) 行第 \(j\) 列元素的翻转次数。
如果翻转操作次数最少的操作方案不唯一,则输出字典序最小的方案。
如果不存在合理方案,则输出 IMPOSSIBLE
。
数据范围
\(1≤M,N≤15\)
输入样例:
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
输出样例:
0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0
思路
枚举第一行可能的情况,尝试翻转下一行,使当前行为 \(0\) ,翻转时统计最小反转次数,同时更新要反转的方案
代码
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int g[N][N],backup[N][N];
int cnt,ans[N][N],num[N][N];
int dx[]={-1,0,1,0,0},dy[]={0,1,0,-1,0};
int n,m;
void turn(int x,int y)
{
for(int i=0;i<5;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=m)continue;
g[a][b]^=1;
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>backup[i][j];
int res=1e9;
for(int op=0;op<1<<15;op++)
{
int cnt=0;
memcpy(g,backup,sizeof g);
memset(num,0,sizeof num);
for(int i=0;i<n;i++)
if(op>>i&1)
{
turn(0,i);
num[0][i]++;
cnt++;
}
for(int i=0;i<n-1;i++)
{
for(int j=0;j<m;j++)
{
if(g[i][j]==1)
{
turn(i+1,j);
num[i+1][j]++;
cnt++;
}
}
}
bool has_one=false;
for(int i=0;i<m;i++)
if(g[n-1][i]==1){
has_one=true;
break;
}
if(!has_one)
{
if(res>cnt)
{
res=cnt;
memcpy(ans,num,sizeof ans);
}
}
}
if(res==1e9)puts("IMPOSSIBLE");
else
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cout<<ans[i][j]<<" \n"[j==m-1];
}
return 0;
}
本文来自博客园,作者:风雨zzm,转载请注明原文链接:https://www.cnblogs.com/zzmxj/p/17367218.html