NC235250 牛可乐的翻转游戏
题目
题目描述
牛可乐发明了一种新型的翻转游戏!
在一个有 行 列的棋盘上,每个格子摆放有一枚棋子,每一枚棋子的颜色要么是黑色,要么是白色。每次操作牛可乐可以选择一枚棋子,将它的颜色翻转(黑变白,白变黑),同时将这枚棋子上下左右相邻的四枚棋子的颜色翻转(如果对应位置有棋子的话)。
牛可乐想请你帮他判断一下,能否通过多次操作将所有棋子都变成黑色或者白色?如果可以,最小操作次数又是多少呢?
输入描述
第一行两个整数 ,代表棋盘的行数和列数。
之后 行,每行 个数字,第 个数字如果为 ,代表对应位置的棋子为白色,如果为 则为黑色。
输出描述
如果无法将所有棋子变成一个颜色,输出 "Impossible"(不含引号),否则输出变成一个颜色的最小操作次数。
示例1
输入
4 4 1001 1101 1001 1000
输出
4
题解
知识点:枚举,状压,递推。
首先注意到可以通过对第 行操作第 行全部按灭或按亮,于是可以通过这个操作将状态变换成最后一行的亮灭,而前三行统一亮灭。而基于这些操作的最后一行如果不是全灭或全亮就说明初状态不可行,否则可行。
然后,对于第一行会有 种初状态,只要遍历这些状态,分别执行上述操作即可。
具体操作上,可以用一个 位二进制 表示对 行灯的开关操作, 表示按, 表示不按。对于 行的状态 而言,需要将 的位置取反且周围 个也取反, 的位置不变,即 ;对于 行的状态 而言,即 ,观察这个性质,我们可以将下一次按钮方式设置为本行的灯状态,做到用下一行按本行的灯;对于 行的状态 而言,即 。需要注意 可能在int里面使范围外的二进制码改变需要加上限制 。
最后计算 可以消去二进制最后一位 来计数。
时间复杂度
空间复杂度
本题为POJ1753的变种。
代码
#include <bits/stdc++.h> using namespace std; int n,m; int a[107],b[107],cur[107],change[107]; int cal(int num){ int ans = 0; while(num){ ans++; num &= num-1; } return ans; } int sol(int a[]){ int ans = ~(1<<31); for(change[0] = 0;change[0]<(1<<m);change[0]++){ int sum = 0; cur[0] = a[0]; for(int i = 0;i<n;i++){ sum += cal(change[i]); cur[i] = cur[i] ^ change[i] ^ (change[i]>>1) ^ ((change[i]<<1)&((1<<m)-1)); cur[i+1] = a[i+1] ^ change[i]; change[i+1] = cur[i]; } if(!cur[n-1]) ans = min(ans,sum); } return ans; } int main(){ std::ios::sync_with_stdio(0); cin>>n>>m; for(int i = 0;i<n;i++){ for(int j = 0;j<m;j++){ char tmp; cin>>tmp; if(tmp == '1') a[i] |= (1<<j); else if(tmp == '0') b[i] |= (1<<j); } } int ans = min(sol(a),sol(b)); if(ans>n*m) cout<<"Impossible"<<'\n'; else cout<<ans<<'\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16280128.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)