1.Fliptile
Sample Input
4 4 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1
Sample Output
0 0 0 0 1 0 0 1 1 0 0 1 0 0 0 0
题意:在题目输入的矩阵,在这个矩阵的基础上,通过最少基础反转,可以将矩阵元素全部变为0,如果不能达到目标则输出"IMPOSSIBLE",达到目标则输出一个操作最少次数的矩阵。
思路:由于在同一个位置翻转两次的话,相当于没有翻转,所以每一个位置有且仅能最多翻转一次,想要将矩阵某个位置的1变为0,只能通过操作下一行同一列的位置,可以对第一行的元素按照要求翻转多次,次数为2^m(m为矩阵的列数),直到所有的情况都尝试过。
下面是AC代码:
#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
int mp[20][20];
int ans[20][20];
int temp_ans[20][20];
int temp[20][20];
int n,m;
int mi=123456789;
void fi(int x,int y)//翻转本身和相邻位置
{
temp[x][y]^=1;
temp[x-1][y]^=1;
temp[x+1][y]^=1;
temp[x][y+1]^=1;
temp[x][y-1]^=1;
}
bool isok()
{
for(int i=0;i<m;i++){
if(temp[n-1][i]) return 0;
}
return 1;//判断翻转是否合理
}
void solve()
{
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>mp[i][j];
}
}
int k=(1<<m);
int count=0;
while(k--)
{
memset(temp_ans,0,sizeof(temp_ans));
memcpy(temp,mp,sizeof(mp));
int cnt=0;
int dy=0;
while((1<<dy)<=count)
{
if((1<<dy)&count)
{
cnt++;
temp_ans[0][dy]=1;//多次不同情况翻转第一行
fi(0,dy);
}
dy++;
}
count++;
for(int i=0;i<n-1;i++){
for(int j=0;j<m;j++){
if(temp[i][j])
{
temp_ans[i+1][j]=1;//记录翻转位置
fi(i+1,j);//翻转下一个位置
cnt++;//记录翻转次数
}
}
}
if(cnt<mi&&isok())//判断
{
mi=cnt;//更新最优解
memcpy(ans,temp_ans,sizeof(temp_ans));
}
}
if(mi>1234567)//代表没找到合理解
{
cout<<"IMPOSSIBLE\n";
}
else//输出优解答案
{
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<ans[i][j]<<" ";
}
cout<<"\n";
}
}
}
int main()
{
int t;
t=1;
while(t--){
solve();
}
return 0;
}