• 费解的开关


    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
    ",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
    ",ans);
    		else puts("-1");
    	}
        return 0;
    }
    
    
  • 相关阅读:
    导弹拦截版
    [USACO1.5]数字三角形 Number Triangles
    FBI树
    修复公路
    台阶问题
    阶乘问题
    连续自然数和
    又是毕业季I
    生活大爆炸版石头剪刀布
    曹冲养猪
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11253790.html
Copyright © 2020-2023  润新知