• P3956 棋盘


    最近在做广搜的题,一场六六欢乐赛彻底让我意识到了暴搜的重要性 所以我为什么要去做广搜。想着先把广搜的黄题刷完(听同学说广搜的橙题更难),结果这一道题我就调了大概4个小时,还是写一篇博客吧

    拿到这道题,最开始是没啥思路的,因为这种题型其实是没怎么遇见过的,之前做过的大多广搜题都是基本上直接套模板,多做这种题加深理解和锻炼思维吧

    最开始的思路还是先用DFS暴搜一下。函数中放四个参数,前两个参数为最基础的坐标,第三个为目前的花费,第四个记录当前是否使用魔法:对于相同颜色的情况,花费不变;对于颜色不同的情况(有颜色),花费+1;对于空白情况,花费+2,并把下一个位置涂上色(最开始没加这个调了很久)。这样的话就得到了第一个程序(60分)

    #include<bits/stdc++.h>
    using namespace std;
    int m,n;
    int a[105][105];
    bool b[105][105];
    int ans=20040915;    //初始化为妹子的生日(玄学优化)
    int mx[4]={1,0,0,-1};
    int my[4]={0,-1,1,0};
    void dfs(int x,int y,int sum,bool op){
    	if(sum>ans) return;
    	if(x==m&&y==m){
    		ans=min(ans,sum);
    		return;
    	}
    	for(register int i=0;i<4;i++){
    		int nx=x+mx[i];
    		int ny=y+my[i];
    		if(nx>=1&&nx<=m&&ny>=1&&ny<=m&&b[nx][ny]==false){
    			if(a[nx][ny]==a[x][y]){
    				b[nx][ny]=true;
    				dfs(nx,ny,sum,false);
    				b[nx][ny]=false;
    			}else if(a[nx][ny]==0&&op==false){
    				b[nx][ny]=true;
    				a[nx][ny]=a[x][y];
    				dfs(nx,ny,sum+2,true);
    				a[nx][ny]=0;
    				b[nx][ny]=false;
    			}else if(a[nx][ny]!=a[x][y]&&a[nx][ny]){
    				b[nx][ny]=true;
    				dfs(nx,ny,sum+1,false);
    				b[nx][ny]=false;
    			}
    		}
    	}
    }
    int main(){
    	scanf("%d%d",&m,&n);
    	for(register int i=1;i<=n;i++){
    		int x,y,c;
    		scanf("%d%d%d",&x,&y,&c);
    		a[x][y]=c+1;
    	}
    	b[1][1]=true;
    	dfs(1,1,0,false);
    	if(ans==20040915){
    		cout<<-1;
    	}else{
    		cout<<ans;
    	}
    	return 0;
    }
    

    然后继续想,发现有个记忆化搜索这种东西,开一个f数组,对于搜索的当前坐标,记录到此坐标的最小化费,对于之后大于它的花费,直接return,最后的答案就是 f [ m ][ m ](70分)

    #include<bits/stdc++.h>
    using namespace std;
    int m,n;
    int a[105][105];
    bool b[105][105];
    int mx[4]={1,0,0,-1};
    int my[4]={0,-1,1,0};
    int f[105][105];
    inline void dfs(int x,int y,int sum,bool op){
    	if(sum>f[x][y]) return;
    	f[x][y]=sum;
    	for(register int i=0;i<4;i++){
    		int nx=x+mx[i];
    		int ny=y+my[i];
    		if(nx>=1&&nx<=m&&ny>=1&&ny<=m&&b[nx][ny]==false){
    			if(a[nx][ny]==a[x][y]){
    				b[nx][ny]=true;
    				dfs(nx,ny,sum,false);
    				b[nx][ny]=false;
    			}else if(a[nx][ny]==0&&op==false){
    				b[nx][ny]=true;
    				a[nx][ny]=a[x][y];
    				dfs(nx,ny,sum+2,true);
    				a[nx][ny]=0;
    				b[nx][ny]=false;
    			}else if(a[nx][ny]!=a[x][y]&&a[nx][ny]){
    				b[nx][ny]=true;
    				dfs(nx,ny,sum+1,false);
    				b[nx][ny]=false;
    			}
    		}
    	}
    	return ;
    }
    int main(){
    	scanf("%d%d",&m,&n);
    	for(register int i=1;i<=m;i++) fill(f[i]+1,f[i]+1+m,20040915);
    	for(register int i=1;i<=n;i++){
    		int x,y,c;
    		scanf("%d%d%d",&x,&y,&c);
    		a[x][y]=c+1;
    	}
    	b[1][1]=true;
    	dfs(1,1,0,false);
    	if(f[m][m]==20040915){
    		puts("-1");
    	}else{
    		printf("%d",f[m][m]);
    	}
    	return 0;
    }
    

    请教了旁边zjy的大佬,他用的是广搜,但是这道题我自己编的广搜连样例都不了(菜),最后选择看了题解,发现对于每次答案的判断应该放在判断越界之后的if语句中,放在外面的话起到的优化作用其实并不大。然后恭喜你,有95分了,我也不知道为什么会第一个数据WA掉,下载了数据之后,特判了一下m=1的情况,直接输出0,这样你就成功AC了

    #include<bits/stdc++.h>
    using namespace std;
    int m,n;
    int a[105][105];
    bool b[105][105];
    int mx[4]={-1,0,1,0};
    int my[4]={0,-1,0,1};
    int f[105][105];
    inline void dfs(int x,int y,int sum,bool op){
    	if(sum>f[x][y]) return;
    	for(register int i=0;i<4;i++){
    		int nx=x+mx[i];
    		int ny=y+my[i];
    		if(sum>f[x][y]) return ;
    		if(nx>=1&&nx<=m&&ny>=1&&ny<=m&&b[nx][ny]==false){
    			if(a[nx][ny]==a[x][y]&&sum<f[nx][ny]){    //之后的判断要写<,别写成<=,会增加时间复杂度 
    				b[nx][ny]=true;
    				f[nx][ny]=sum;
    				dfs(nx,ny,sum,false);
    				b[nx][ny]=false;
    			}else if(a[nx][ny]==0&&op==false&&sum+2<f[nx][ny]){
    				b[nx][ny]=true;
    				a[nx][ny]=a[x][y];
    				f[nx][ny]=sum+2;
    				dfs(nx,ny,sum+2,true);
    				a[nx][ny]=0;
    				b[nx][ny]=false;
    			}else if(a[nx][ny]!=a[x][y]&&a[nx][ny]&&sum+1<f[nx][ny]){
    				b[nx][ny]=true;
    				f[nx][ny]=sum+1;
    				dfs(nx,ny,sum+1,false);
    				b[nx][ny]=false;
    			}
    		}
    	}
    	return ;
    }
    signed main(){
    	scanf("%d%d",&m,&n);
    	if(m==1){
    		cout<<0;
    		return 0;
    	}
    	for(register int i=1;i<=m;i++) fill(f[i]+1,f[i]+1+m,20040915);
    	for(register int i=1;i<=n;i++){
    		int x,y,c;
    		scanf("%d%d%d",&x,&y,&c);
    		a[x][y]=c+1;
    	}
    	b[1][1]=true;
    	dfs(1,1,0,false);
    	
    	if(f[m][m]==20040915){
    		puts("-1");
    	}else{
    		printf("%d",f[m][m]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    EncodeLDPC校验矩阵H的高斯变换
    Linuxubuntu学习(一)
    tcp通信
    HTTP协议,超文本传输协议
    局部变量成员变量
    线程
    正则表达式
    面向对象
    String类
    Object类
  • 原文地址:https://www.cnblogs.com/Poetic-Rain/p/13095542.html
Copyright © 2020-2023  润新知