Sereja has an n × m rectangular table a, each cell of the table contains a zero or a number one. Sereja wants his table to meet the following requirement: each connected component of the same values forms a rectangle with sides parallel to the sides of the table. Rectangles should be filled with cells, that is, if a component form a rectangle of size h × w, then the component must contain exactly hwcells.
A connected component of the same values is a set of cells of the table that meet the following conditions:
- every two cells of the set have the same value;
- the cells of the set form a connected region on the table (two cells are connected if they are adjacent in some row or some column of the table);
- it is impossible to add any cell to the set unless we violate the two previous conditions.
Can Sereja change the values of at most k cells of the table so that the table met the described requirement? What minimum number of table cells should he change in this case?
The first line contains integers n, m and k (1 ≤ n, m ≤ 100; 1 ≤ k ≤ 10). Next n lines describe the table a: the i-th of them contains mintegers ai1, ai2, ..., aim (0 ≤ ai, j ≤ 1) — the values in the cells of the i-th row.
Print -1, if it is impossible to meet the requirement. Otherwise, print the minimum number of cells which should be changed.
5 5 2 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
1
3 4 1 1 0 0 0 0 1 1 1 1 1 1 0
-1
3 4 1 1 0 0 1 0 1 1 0 1 0 0 1
0
给出一个n*m的01矩阵,我们最多可以将矩阵中K个位子上的数翻转(0->1 1->0);
问我们最少操作多少次,能够使得每一个联通块都是矩形。如果不存在方案,输出-1.
思路:
①我们知道,对于一个可行方案来讲,第一行上边的情况,要么和其他各行上边的情况相同,要么和其他各个行上边的情况相反。
②进而观察到数据范围,K不大,那么不妨分情况讨论:
1.如果n>K,那么我们肯定至少有一行不会被改变过,那么我们O(n)枚举这样的一行,从而就能够判断出其他各行应该如何去改变,时间复杂度O(n^2*m);
2.如果n<=K,那么我们肯定需要将矩阵翻转过去,然后对于第一行的数据进行O(2^K)枚举每个位子是否进行改变。从而再通过这一行的结果去判断其他各行应该如何去改变,时间复杂度O(2^k*n*m);
过程维护一下即可。
值得注意的点是,我们当前矩阵进行了上述操作取了最小值之后,我们应该再将矩阵翻转一遍,再去做一遍上述过程取整体最小才行。
简单的说就是形状会影响某种情况操作的结果的大小,所以还需要翻转一次取所有方案中的最小值。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int b[150][150];
int a[150][150];
int n,m,T,ans;
void Slove()
{
if(n>T)
{
int output=0x3f3f3f3f;
for(int z=1; z<=n; z++)
{
int sum=0;
for(int i=1; i<=n; i++)
{
int cnt=0;
for(int j=1; j<=m; j++)
{
if(a[i][j]!=a[z][j])cnt++;
}
int cnt2=0;
for(int j=1; j<=m; j++)
{
if(a[i][j]==a[z][j])cnt2++;
}
sum+=min(cnt,cnt2);
}
output=min(output,sum);
}
ans=min(ans,output);
}
else if(m<=T)
{
int output=0x3f3f3f3f;
for(int z=0; z<(1<<T); z++)
{
int sum=0;
for(int i=2; i<=n; i++)
{
int cnt=0;
for(int j=1; j<=m; j++)
{
if((z&(1<<(j-1)))>0)
{
if(a[i][j]==a[1][j])cnt++;
}
else if(a[i][j]!=a[1][j])cnt++;
}
int cnt2=0;
for(int j=1; j<=m; j++)
{
if((z&(1<<(j-1)))>0)
{
if(a[i][j]!=a[1][j])cnt2++;
}
else if(a[i][j]==a[1][j])cnt2++;
}
sum+=min(cnt,cnt2);
}
int temp=0;
for(int i=1; i<=m; i++)
{
if((z&(1<<(i-1)))>0)temp++;
}
output=min(output,sum+temp);
}
ans=min(ans,output);
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&T))
{
ans=0x3f3f3f3f;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%d",&a[i][j]);
b[i][j]=a[i][j];
}
}
Slove();
int x=1,y=1;
for(int i=1; i<=m; i++)
{
for(int j=n; j>=1; j--)
{
a[x][y]=b[j][i];
y++;
if(y>n)y=1,x++;
}
}
swap(n,m);
Slove();
if(ans>T)printf("-1\n");
else printf("%d\n",ans);
}
}