Acwing.95费解的开关

题目

我们很容易想到两点

  • 每一个位置顶多只会操作一次(因为如果操作两次的话,相当于不操作,必然是不满足最优解)
  • 在一套方案中,操作的顺序无关紧要(因为每个按钮是0还是1,只取决于它或它周围的按钮被按下的次数)

我们假定上一行已经不能改变了

那么如果上一行中存在’0’,我们想让它变成’1’,就需要按下一行的按钮;

即若第 i i i行存在’0’,我们现在固定(不按按钮)第 i i i行,要想让这些’0’变成’1’,只能去按 i + 1 i+1 i+1行的按钮;

同理若 i + 1 i+1 i+1行是固定的,要操作只能去操作 i + 2 i+2 i+2行,以此类推;

那么我们想要获得最优解,只需要枚举第一行的所有按法,然后依次递推给下一行,就可以求出所有的方案,取min则得最优解;

Code

#include <iostream>
#include <cstring>

using namespace std;

const int N = 10;

int dx[5] = {0,-1,1,0,0};
int dy[5] = {0,0,0,1,-1};
char str[N][N];
char gstr[N][N];
void change(int x,int y){
    for(int k=0;k<5;++k){
        int i = x+dx[k];
        int j = y+dy[k];
        if(i<1||i>5||j<1||j>5) continue;
        //'0' -> '1' 或 '1' -> '0'
        str[i][j]^=1;
    }
}
void solve(){
    //枚举第一行的按法
    int ans = 7;//>6即可
    for(int i=0;i<(1<<5);++i){
        memcpy(str,gstr,sizeof(str));
        int count = 0;
        for(int j=0;j<5;++j){
            if(i>>j & 1){
                change(1,j+1);
                ++count;
            }
        }
        for(int h=2;h<=5;++h){
            for(int l=1;l<=5;++l){
                if(str[h-1][l] == '1') continue;
                //为0
                change(h,l);
                ++count;
            }
        }
        bool flag = true;
        //现在保证除了最后一行的灯都是全部亮的
        for(int l=1;l<=5;++l){
            if(str[5][l] == '0'){
                flag = false;
                break;
            }
        }
        //只有全部是亮的 并且这个解更加优秀 那么更新ans
        if(flag){
            ans = min(ans,count);
        }
    }
    ans=ans<=6?ans:-1;
    cout << ans << '\n';
}
int main(){
    int t;
    cin >> t;
    while(t--){
        for(int i=1;i<=5;++i){
            cin >> (gstr[i]+1);
        }
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值