题目描述:
题目传送门:http://codeforces.com/contest/1207/problem/B
题目大意:两个值只能为0或1的矩阵,矩阵A是给定的,矩阵B是全为0的。当我们把b[i][j]置1的时候,b[i+1] [j] , b[i] [j+1] , b[i+1] [j+1]都要置1。问翻转几次并且翻转哪几个块能使矩阵A变换为矩阵B。如果矩阵A无法通过变换得到矩阵B,输出-1。如果矩阵A也是全0的(A,B的初始状态相同),输出0。
解题思路:
主要思想还是贪心思想。对A进行遍历,如果A【i】【j】且与它相邻的3个点都是1,且B【i】【j】以及其相邻的三个点(共四个点)中至少有一个不为1(因为都为1就没必要再翻了)。那么就翻转B【i】【j】,以及它相邻的3个点,用数组X和数组Y分别记录所翻转的点的横、纵坐标,需要注意的是坐标是从1开始的,所以记录的实际上是i+1和j+1的值。再定义一个tot变量来记录一下一共需要翻几次。用flag来判断能否最终翻成A。
AC代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
int c=0,d=0,flag=0,n=0,m=0,tot=0,count=0;
cin>>n>>m;
int a[n][m];
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>a[i][j];
int b[n][m];
memset(b,0,sizeof(b));
int x[2505]={0},y[2505]={0};//这个数组的范围一定要注意,不然会超时
//原来的范围是55,结果test5一直超时,后来迷过来了,一共是2500个点而不是50个
//但是为什么会超时呢?
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]==0)
{
count++;
}
}
}
if(count==n*m)
{
cout<<0<<endl;
return 0;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]==1&&a[i+1][j]==1&&a[i][j+1]==1&&a[i+1][j+1]==1&&(b[i][j]==0||b[i+1][j]==0||b[i][j+1]==0||b[i+1][j+1]==0)&&i+1<n&&j+1<m)//注意i+1和j+1的范围
{
b[i][j]=1;
b[i+1][j]=1;
b[i][j+1]=1;
b[i+1][j+1]=1;
x[c]=i+1;
y[c]=j+1;
c++;
// d++;
tot++;
}
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]!=b[i][j])
{
flag=1;
}
}
}
if(flag==0)
{
cout<<tot<<endl;
for(int i=0;i<c;i++)
cout<<x[i]<<" "<<y[i]<<endl;
}
if(flag==1)
cout<<-1<<endl;
return 0;
}
注意事项:
x,y数组的范围一定要给够,要给到2500(实际上用不了那么多),刚开始我给的一直是55……太迷了,超时了好几次不知道原因在哪里。然后就是在判断条件里面,一定别忘了对i+1和j+1的范围做一个限定,分别是小于n和m的,不然会造成数组越界。
还有一个疑问,就是为什么我的x,y数组范围给的不够的时候错误原因是超时呢?希望评论区的大神可以帮忙解答一下这个问题。
问题解答: