题目大意:给出两个$n \cdot m$的矩阵$A$和$B$,一开始矩阵$B$全为0,每次可以选定一个坐标$(x,y)(1 \le x < n、1 \le y < m)$,将$(x,y)、(x,y + 1)、(x + 1,y)、(x + 1,y + 1)$都变成1,求将矩阵$B$变为$A$的最小步数,并输出所有的操作的坐标。
这个思维题又把我卡死了,C题都写得出来但是我写不出这个B,结束前3分钟才给A掉然后没时间写别的了。。
要操作的次数最少,也就是说每次操作要保证改变的0的数量最多
把一个0的位置变成1,假设这个坐标是$(x,y)$,那么可以通过修改$(x - 1,y - 1)、(x - 1,y)、(x,y - 1)、(x,y)$这四个位置来达到
那么每次直接扫描一下$B$中是0但$A$中是1的位置,如果操作的区域中在$A$中没有0,就可以求出一个能使得这次操作最大化的操作位置来进行操作
显然时间复杂度是$O(nm)$的,然后我这里还带了一些常数,但是影响不大
这一场从$\Delta$-80+在最后3分钟拉回来。。最后涨了一分。。。(我还真是个弟弟。。
思维题必杀我
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| int n,m; int a[60][60],b[60][60],cnt = 0;
vector<pair<int,int> > ans;
inline bool check(int x,int y) { if(a[x][y] == 0 || a[x][y + 1] == 0 || a[x + 1][y] == 0 || a[x + 1][y + 1] == 0) return false; return true; }
inline void modify(int x,int y) { b[x][y] = b[x][y + 1] = b[x + 1][y] = b[x + 1][y + 1] = 1; }
bool checkans() { for(int i = 1;i <= n;i++) { for(int j = 1;j <= m;j++) { if(b[i][j] != a[i][j]) return false; } } return true; }
int get_fix(int x,int y) { if(x < 1 || x >= n || y < 1 || y >= m) return 0; else { int cnt = 0; for(int i = 0;i < 2;i++) { for(int j = 0;j < 2;j++) { if(b[x + i][y + j] == 0) cnt++; } } return cnt; } } int main() { ios::sync_with_stdio(0); mst(b,0); cin>>n>>m; for(int i = 1;i <= n;i++) { for(int j = 1;j <= m;j++) { cin>>a[i][j]; } } for(int i = 1;i <= n;i++) { for(int j = 1;j <= m;j++) { if(b[i][j] == 0 && a[i][j] != 0) { int fixed = 0; int posx = 0,posy = 0; for(int k = -1;k <= 0;k++) { for(int l = -1;l <= 0;l++) { if(check(i + k,j + l)) { int tmp = get_fix(i + k,j + l); if(fixed < tmp) { fixed = tmp; posx = i + k;posy = j + l; } } } } if(fixed != 0) { cnt++; modify(posx,posy); ans.push_back(make_pair(posx,posy)); } } } } if(checkans() == false) { cout<<-1<<endl; } else { cout<<cnt<<"\n"; for(auto x : ans) { cout<<x.first<<" "<<x.second<<"\n"; } } return 0; }
|