标签:cnt 第一行 点亮 二进制 费解 ans 第二行 递推 fo
费解的开关(二进制+递推+思维)
- 题意:5*5的灯阵,每次按一盏灯的开关,并且这盏灯的上下左右也受到相同的影响(0->1,1->0),求使给定灯阵全1的最少步数。
- 题解:
- 每盏灯最多点击一次,点击两次相当于没有点击。
- 最重要的性质:如果我们确定了第1行的灯的情况的话,那么后面的行数都可以依此递推,当前行灭的灯只能由下一行同一列的灯使之点亮。
- 附上一个写的较好的题解
举个例子
11011
10110
01111
11111
第一行中第三盏灯为0,那么必须通过第二行的第3张灯将其点亮,当前行的灯只能由下一行的灯点亮,这样才不会影响当前行其他灯的情况。所以只需要确定第一行的灯的情况即可,第一行的灯控制第二行灯的点击情况,通过第二行灯将第一行灭的灯点亮后, 第二行灯处于灭状态的灯由第三行点亮,依次类推
- Code:
//模块化编程思想
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset((a),0,sizeof(a))
#define fo(i,a,b) for(int (i)=(a);(i)<(b);(i)++)
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)//宏定义,编译时展开,占用编译时间
#define sf(x) scanf("%d",&(x))
const int inf=(0x7f7f7f7f);
const int maxn=3000;
int n;
int mp[5][5];
int dx[]={0,-1,0,1,0};
int dy[]={0,0,1,0,-1};
void turn(int x,int y){
fo(i,0,5){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=0&&xx<5&&yy>=0&&yy<5){
mp[xx][yy]^=1;
}
}
}
char mmp[5][5];
int work(){
int ans=(1<<30);
int cnt=0;
//fo(i)循环枚举第一行灯的所有可能的点击情况,10010(表示点击第一盏灯和第四盏灯)
fo(i,0,31){
//初始化,
fo(x,0,5)fo(y,0,5)mp[x][y]=mmp[x][y]-'0';
cnt=0;
//通过二进制数解码出灯的点击情况
fo(j,0,5)
if((i>>j)&1){
cnt++;
turn(0,j);
}
//依次处理前4行灯
fo(j,0,4){
fo(k,0,5){
if(mp[j][k]==0){
turn(j+1,k);//通过下一行的灯使其点亮
cnt++;
}
}
}
//检查第五行灯是否是全亮的情况,如果不是由于前4行是全1的情况
//第五行灭的灯无法点亮,故当前方案不合理
bool is_ok=1;
fo(j,0,5)if(mp[4][j]==0){
is_ok=0;
break;
}
if(is_ok)
ans=min(ans,cnt);
}
if(ans>6)return -1;
return ans;
}
int main(){
sf(n);
while(n--){
fo(i,0,5)scanf("%s",mmp[i]);
//fo(i,0,5)fo(j,0,5)cout<<mmp[i][j];
cout<<work()<<endl;
}
return 0;
}
标签:cnt,第一行,点亮,二进制,费解,ans,第二行,递推,fo 来源: https://www.cnblogs.com/sstealer/p/11123666.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。