tyvj【dfs枚举】【sl】费解的开关

本文详细解析了一种解决矩阵翻转问题的高效算法。通过枚举第一行状态,推导后续行的翻转策略,避免了传统枚举方法的超时问题。适用于求解特定条件下,将01矩阵转换为全1矩阵所需的最少步骤。

题目链接

题目大意

有n个5* 5的01矩阵,你可以选择一个矩阵中的位置,使此位置和其上下左右总共5个数取反。求从给出的矩阵变换到全是1的矩阵需要多少步,如果结果大于六步,输出-1。


如果一个一个枚举的话肯定是超时的。
所以:
已知“一个点不可以点两次”
我们可以先枚举第一行的状态(O(2^5)),枚举完之后,如果第一行存在0,那么得出第二行的这个位置必须点,其它位置不可以点(因为这样就会把第一行的其它1变成0了),由此得到第二行的状态,接着又可以推出第三行必须点的地方…推到第五行,看看是否符合条件就可以了。(O(25))


#include<cstdio>
int a[7][7],k[7][7],js,ans,n;
char c;
void cl(int d){   //翻第i行第d个数
    a[1][d]^=1;
    a[1][d-1]^=1;
    a[1][d+1]^=1;
    a[2][d]^=1;
}
void work(){
	int kkk=js;   //保护我计数变量
    for(int i=1;i<5;++i)  //枚举
        for(int j=1;j<=5;++j)
          if(k[i][j]==0){   //如果它是0,翻下一行这个位置的数
              k[i][j]^=1;
              k[i+1][j]^=1;
              k[i+1][j-1]^=1;
              k[i+1][j+1]^=1;
              k[i+2][j]^=1;
              ++kkk;  //需要的步数+1
          }
    for(int i=1;i<=5;++i)  //判断一下是否符合条件
      if(k[5][i]==0)
      	return;
    if(kkk<ans) ans=kkk;  //记一下
}
void s(int d){   //枚举第一行第d个位置是否点
    if(d>5){  //第一行处理完毕
    	for(int i=1;i<=5;++i)  //找个替身,保护我a数组状态
    	  for(int j=1;j<=5;++j)
    	    k[i][j]=a[i][j];
    	work();  //推
    	return;
    }
    s(d+1);  //不翻
    cl(d);  //翻的操作
    ++js;   //计翻的次数
    s(d+1);  //翻
    --js;   //重置
    cl(d);
}
int main(){
    scanf("%d",&n);
    while(n>0){  //矩阵数
    	ans=7;
        for(int i=1;i<=5;++i)  //读入
          for(int j=1;j<=5;++j)
          	scanf("%1d",&a[i][j]);  //1位
        s(1);  //枚举第一行第1位是否要翻。
        if(ans>6) printf("-1\n");  //答案数>6,如题
        else printf("%d\n",ans);
        --n;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值