【dfs】Vijos 1197 费解的开关

链接

https://vijos.org/p/1197

大意

给定一个01矩阵,对每个格子都可以进行取反操作,但一取反,周围的格子也必定取反,求最小步数

思路

暴力搜索的话时间复杂度为 O(n2×(n1)!) O ( n 2 × ( n − 1 ) ! )

我们仔细观察可以发现两个性质

1,每个点至多被点击一次
2. 若一行无法全部点亮则只能点亮下一行的灯

利用这两个性质,我们可以枚举第一行点灯的情况再进行递推

时间复杂度: O(n2×2n)=O(2532)=O(800) O ( n 2 × 2 n ) = O ( 25 ∗ 32 ) = O ( 800 )
可以通过本题

代码

#include
using namespace std;int t,a[6][6],k=0,b[6][6],ans=7;
bool ok;
inline void add(register int x,register int y)
{
    b[x][y]^=1;
    if(x>1)b[~-x][y]^=1;
    if(x<5)b[x+1][y]^=1;
    if(y>1)b[x][~-y]^=1;
    if(y<5)b[x][y+1]^=1;
    k++;
    return;
}
inline bool check(register int x)
{
    if(x==5)//到达最后一行
    {
        for(register int i=1;i<6;i++)
        if(!b[x][i]) return false;
        return true;
    }
    for(register int i=1;i<6;i++) if(!b[x][i]) add(x+1,i);//改变
    return check(x+1);//递推
}
signed main()
{
    scanf("%d",&t);
    while(t--)
    {
        ans=7;//最多有六步
        for(register int i=1;i<6;i++)
         for(register int j=1;j<6;j++)
          {scanf("%1d",&a[i][j]);b[i][j]=a[i][j];}
        for(register int i=0;i<32;i++)
        {
            int x=i,j=5;k=0;
            while(x)
            {
                if(x&1) add(1,j);//改变
                x>>=1;j--;
            }
            if(check(1))if(k//取最小值
            for(register int x=1;x<6;x++)for(register int y=1;y<6;y++)b[x][y]=a[x][y];
        }
        if(ans==7) printf("-1\n");
        else printf("%d\n",ans);
    }
}

你可能感兴趣的:(dfs)