藍橋杯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
相關文章
相關標籤/搜索