• 蓝桥杯dfs搜索专题


    2018激光样式

    #include<bits/stdc++.h>
    using namespace std;
    
    /*
    dfs(i) 第i个激光机器 有两种选择:vis[i-1] == 0 时 可选,无论vis[i-1]为何值都不选 
    vis[i] 回溯标记是否用过 
    */ 
    int n = 30;
    int vis[35];
    int ans = 0;
    int dp[35];
    
    
    void dfs(int x){
    	
    	if(x == n+1){
    		ans++;
    		return;
    	}
    	
    	dfs(x+1); //这个点不开激光 
    	if(vis[x-1] == 0){//前一个点没开激光 那么这个点可以开激光: vis[x] = 1就表示开激光 
    		vis[x] = 1;
    		dfs(x+1);
    		vis[x] = 0;//回溯
    	}
    }
    
    int main(){
    	for(int i=1;i<=30;i++) vis[i] = 0;
    	dfs(1);
    	cout<<ans<<endl;
    	return 0;
    }
    //2178309
    

     
     

    2017磁砖样式

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m;
    const int maxn = 10;
    int g[maxn][maxn]; 
    vector<int> v;
    set<vector<int> > se;
    set<vector<int> > se2;
    map<int, int> Hash;
    int ans = 0;
    
    bool check_color() {
        for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= m; j++) {
            if(i+1 <= n && j+1 <= m) {
            	//1 1 1 1  2 2 2 2    1 2 1 2  
                if((g[i][j]+g[i][j+1]+g[i+1][j]+g[i+1][j+1]) % 4 == 0) 
                    return false;
            }
        }
        return true;
    }
    
    bool check2(){
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(g[i][j] == 0){
    				return false;
    			}
    		}
    	}
    	
    	for(int i=1;i<=n-1;i++){
    		for(int j=1;j<=m-1;j++){
    			int aa = g[i][j];
    			int bb = g[i+1][j];
    			int cc = g[i][j+1];
    			int dd = g[i+1][j+1]; 
    			if(aa == bb && aa ==cc && bb== cc && cc == dd && bb == dd && aa == dd){
    				return false;
    			}
    		}
    	}
    	return true;
    }
    
    bool check(){
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(g[i][j] == 0){
    				return false;
    			}
    		}
    	}
    	
    	for(int i=1;i<=n-1;i++){
    		for(int j=1;j<=m-1;j++){
    			if(g[i][j] == g[i+1][j] == g[i][j+1] == g[i+1][j+1])
    				return false;
    		}
    	}
    	return true;
    }
    
    void dfs(int x,int y){
    	if(x == n+1 && y == 1){
    //		for(int i=1;i<=n;i++){
    //			for(int j=1;j<=m;j++){
    //				cout<<g[i][j]<<" ";
    //			}
    //			cout<<endl;
    //		}
    		
    		if(check_color()){
    			v.clear();
    			for(int i=1;i<=n;i++){
    				for(int j=1;j<=m;j++){
    					v.push_back(g[i][j]);
    				}
    			}
    			se.insert(v);
    		}
    		if(check2()){
    			v.clear();
    			for(int i=1;i<=n;i++){
    				for(int j=1;j<=m;j++){
    					v.push_back(g[i][j]);
    				}
    			}
    			se2.insert(v);
    		}
    		return;
    	}
    	
    	if(g[x][y]){
    		if(y == m)
    			dfs(x+1,1);
    		else
    			dfs(x,y+1);
    	}else{
    		if(y+1 <= m && !g[x][y+1]){
    			for(int i=1;i<=2;i++){
    				g[x][y+1] = i;
    				g[x][y] = i;
    				if(y == m){
    					dfs(x+1,1);
    				}else{
    					dfs(x,y+1);
    				}
    				g[x][y] = 0;
    				g[x][y+1] = 0;
    			}
    		}
    		if(x+1 <= n && !g[x+1][y]){
    			for(int i=1;i<=2;i++){
    				g[x+1][y] = i;
    				g[x][y] = i;
    				if(y == m){
    					dfs(x+1,1);
    				}else{
    					dfs(x,y+1);
    				}
    				g[x+1][y] = 0;
    				g[x][y] = 0;
    			}
    		}
    	}
    }
    
    int main(){
    	n = 3, m =10;
    	dfs(1,1);
    	cout<<se2.size()<<endl; 
    	cout<<se.size()<<endl;
    	set<vector<int> >::iterator it = se2.begin();
    	vector<int> vv;
    	while(it != se2.end()){
    		if(se2.find(*it) != se2.end() && se.find(*it) == se.end() ){
    			vv = *it;
    			break;
    		}
    		it++;
    	}
    	int t = 0;
    	for(int i=0;i<vv.size();i++){
    		if(t == 10) {
    			t = 0;
    			cout<<endl;
    		}
    		cout<<vv[i]<<" ";
    		t++;
    	}
    	cout<<endl;
    	return 0;
    }
    //123996我的答案 check函数 是错的?!!  check2函数是对的 
    //101466网上答案 是对的!!
    //原因:检查颜色的函数出错 为什么? 不能连等判断。。。。。这语法 
    //已改正 
    /*
    1 1 1 1 1 1 1 1 1 1
    1 2 1 2 2 1 2 2 1 2
    1 2 2 2 2 2 1 1 1 2
    */
    

     
     

    2016凑平方数

    #include<bits/stdc++.h>
    using namespace std;
    
    
    /*
    分成几组? k组 1 ~ 10;
    每组:dfs搜索0~9这几个没用过的数; 
    	if 完全平方数 
    		1.x+1
    		2.继续加值 (0不能作为第一个数 单独考虑)
    到了k组 先对结果排序存到vector数组中 再set去重(因为递归回溯 结果有大量重复)
    
    注意:必须用long long...用int会出错 因为int的取值范围为:-2147483648 ~ 2147483647 
    */ 
    typedef long long ll;
    int vis[15];
    ll a[15];
    vector<ll> v;
    int vis2[10];
    int k;
    int ans = 0;
    set<vector<ll> > se;
    
    inline bool check(ll x){
    	if(x == 9814072356){
    		int eeeeee = 1;
    	}
    	double d = sqrt(x);
    	return d == (ll)d;
    }
    
    //因为递归回溯有大量重复  改成set去重 
    void dfs(int x,ll cur){
    	if(x == k){
    		for(int i=0;i<10;i++){
    			vis2[i] = 0;
    		}
    		for(int i=0;i<k;i++){
    			ll d = a[i];
    			if(d == 0) vis2[d] = 1;
    			else{
    				while(d){
    					vis2[d%10] = 1;
    					d = d/10;
    				}
    			}
    		}
    		for(int i=0;i<=9;i++){
    			if(!vis2[i]) return;
    		}
    		for(int i=0;i<k;i++) v.push_back(a[i]);
    		sort(v.begin(),v.end());
    		if(se.find(v) == se.end()){
    			for(int i=0;i<k;i++) cout<<v[i]<<" ";
    			cout<<endl;
    			se.insert(v);
    		}
    		v.clear();
    		ans++;
    		return;
    	}
    	
    	for(int i=0;i<=9;i++){
    		if(!vis[i]){
    			vis[i] = 1;
    			if(cur == 0 && i == 0){//如果是以0开头 并且当前搜索的是一个新的分组(cur值为0) 就直接搜索下一组 
    				a[x] = 0;
    				dfs(x+1,0);
    				vis[i] = 0;
    				continue;
    			}
    			ll num = cur*10+i;
    			if(check(num)){
    				a[x] = num;
    				dfs(x+1,0);
    			} //搜索下一分组 
    			dfs(x,cur*10+i);//继续搜索当前分组
    			vis[i] = 0;
    		}
    	}
    }
    
    int main(){
    	//freopen("out1.txt","w",stdout);
    	//枚举分组的次数 
    	for(k = 1;k <= 10;k++){
    		memset(vis,0,sizeof(vis)); 
    		dfs(0,0);
    	}
    	cout<<ans<<endl;
    	cout<<se.size()<<endl;
    	return 0;
    } 
    //3085
    //300  
    

     
     

    2015完美正方形

    #include<bits/stdc++.h>
    using namespace std;
    
    int n = 47 + 46 + 61;//边长 
    int a[19] = {2, 5, 9, 11, 16, 17, 19, 21, 22, 24, 26, 30, 31, 33, 35, 36, 41, 50, 52};
    int g[500][500];//大正方形地图 
    int vis[30];
    set<int> se;//集合存储正方形最后一行边长数据结果
    
    void fill(int x,int y,int l,int num){
    	for(int i=x;i<=x+l-1;i++){
    		for(int j=y;j<=y+l-1;j++){
    			g[i][j] = num;
    		}
    	}
    }
    
    bool ok(int x,int y,int l){
    	if(x+l-1 > n) return false;
    	if(y+l-1 > n) return false;
    	for(int i=x;i<=x+l-1;i++){
    		for(int j=y;j<=y+l-1;j++){
    			if(g[i][j] != 0) return false;
    		}
    	}
    	return true;
    }
    
    bool check(){
    	return true;
    }
    
    void dfs(int x,int y){
    	if(x == n+1){//递归出口 
    		if(check()){
    			for(int i=1;i<=n;i++){
    				se.insert(g[n][i]);//set集合存储最后一层正方形边长数据 
    			}
    		}
    		return;
    	}
    	if(g[x][y] != 0 ){//当前正方形填充过了 
    		if(y == n) 
    			dfs(x+1,1);//dfs下一个 
    		else 
    			dfs(x,y+1);//dfs下一个 
    	}else{//当前正方形没有填充过 
    		for(int i=0;i<19;i++){//枚举19块正方形 
    			if(!vis[i]){
    				if(ok(x,y,a[i])){
    					fill(x,y,a[i],a[i]);//填充正方形成a[i]边长 以(x,y)为左上顶点 
    					vis[i] = 1;
    					if(y == n){
    						dfs(x+1,1);//dfs下一个 
    					}else{
    						dfs(x,y+1);//dfs下一个 
    					}
    					vis[i] = 0;//回溯 
    					fill(x,y,a[i],0);//填充正方形成0 以(x,y)为左上顶点
    				}else{
    					break;//剪枝 因为a数组按顺序排的 当前边长不行 后面边长更不行了 
    				}
    			}
    		}
    	}
    
    }
    
    int main(){
    	fill(1,1,47,47);//填充以(1,1)为左上顶点的正方形 边为47 
    	fill(1,47+1,46,46);
    	fill(1,47+46+1,61,61);
    	dfs(1,1);//从(1,1)点开始搜索 
    	set<int>::iterator it = se.begin();
    	while(it!=se.end()){
    		cout<<*it<<" ";
    		it++;
    	}
    	return 0;
    } 
    //30 33 41 50
    

     
     

  • 相关阅读:
    JavaWeb工程中web.xml基本配置
    json
    理解文档对象模型(3)
    关于经验模态分解的混叠模态(mode mixing)问题
    android ListView SimpleAdapter 带图片
    JAVA的类和对象
    JAVA的循环结构进阶
    JAVA的数组
    JAVA的循环结构
    JAVA的选择结构(二)
  • 原文地址:https://www.cnblogs.com/fisherss/p/10897941.html
Copyright © 2020-2023  润新知