码迷,mamicode.com
首页 > 其他好文 > 详细

费解的开关

时间:2019-07-27 09:25:49      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:==   i+1   mat   改变   输出   stream   main   https   开始   

AcWing

题意:给出一个\(5×5\)矩形网格图,\(a[i][j]\)表示第i行第j列的数字(只能为0或者1),每次操作可以选择一个位置,对于该个位置以及其上下左右个一个位置上的数字0变成1,1变成0,询问是否能少于6次将所有数字变为1,如果能,请输出最少次数,否则输出“-1”.

分析:思路一:倒序BFS:把每个状态看成一个25位的二进制数,从最终状态也就是全部位都为1开始BFS,把6步之内能走到的状态用map记下,就可以\(O(1)\)回答每个询问了.但是BFS会超时...但还是放一下代码,看看能不能优化.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
map<int,int>Map;
queue<int>q;
inline int get_map(int x,int i){//对于状态x,我按下第i位,会变成什么状态?
    x=x^(1<<i);
    if((i%5)<4)x=x^(1<<(i+1));
    if(i%5)x=x^(1<<(i-1));
    if(i>=5)x=x^(1<<(i-5));
    if(i<20)x=x^(1<<(i+5));
    return x;
}
inline void bfs(){
    q.push((1<<25)-1);Map[(1<<25)-1]=0;
    while(!q.empty()){
        int now=q.front();q.pop();
        if(Map[now]==7)return;
        for(int i=0;i<25;++i){
            int res=get_map(now,i);
            if(!Map[res]){
                Map[res]=Map[now]+1;
                q.push(res);
            }
        }
    }
}
int main(){
    bfs();
    int T=read();
    while(T--){
        int cnt=0;
        for(int i=0;i<25;++i){
            char ch;cin>>ch;
            cnt+=((ch-'0')<<i);
        }
        if(Map[cnt])printf("%d\n",Map[cnt]);
        else puts("-1");
    }
    return 0;
}

思路二:DFS:挖掘题目性质,若我们固定了第一行,则点击方案唯一,因为若第二行某一位为0,只能通过点击第三行的该位来改变,每一行这样递推下去,如果最后一行的状态不全为1,说明本次对第一行的点击方式不合法.综上,所以我们DFS对第一行点击方式的枚举,然后每次check这次点击方式是否合法就行了,如果合法就比较最小步数.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int ans,a[10][10],b[10][10];
inline int check(int now){
    int sum=now;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            b[i][j]=a[i][j];
    for(int i=1;i<=4;i++)
        for(int j=1;j<=5;j++)
            if(!b[i][j]){
                ++sum;
                b[i][j]^=1;
                b[i+1][j]^=1;
                b[i+1][j-1]^=1;
                b[i+1][j+1]^=1;
                b[i+2][j]^=1;
            }
    for(int i=1;i<=5;i++)if(!b[5][i])return 1e9; 
    return sum;
}
inline void dfs(int lie,int now){
    if(lie>5){
        ans=min(ans,check(now));
        return;
    }//第一行点击方式枚举完毕
    a[1][lie]^=1;a[1][lie-1]^=1;a[1][lie+1]^=1;a[2][lie]^=1;
    dfs(lie+1,now+1);//点击第一行第lie列,步数now+1
    a[1][lie]^=1;a[1][lie-1]^=1;a[1][lie+1]^=1;a[2][lie]^=1;
    dfs(lie+1,now); //回溯,也就是不点击第一行第lie列
    return;
}
int main(){
    int T=read();
    while(T--){
        for(int i=1;i<=5;++i)
            for(int j=1;j<=5;++j){
                char ch;cin>>ch;
                a[i][j]=ch-'0';
            }
        ans=1e9;dfs(1,0);
        if(ans<=6)printf("%d\n",ans);
        else puts("-1");
    }
    return 0;
}

费解的开关

标签:==   i+1   mat   改变   输出   stream   main   https   开始   

原文地址:https://www.cnblogs.com/PPXppx/p/11253790.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!