• UVA


    题目:

    输入一个n*m的棋盘(n,m<10),某些格子有标记,用最少的皇后守卫(即占据或攻击)所有的标记的格子。输出皇后的个数。

    思路:

    一开始没有想到用迭代加深搜索,直接dfs结果还没写完就发现这样要枚举的量太大了……于是换用迭代加深搜索。对于每个格子有四个方向可以用i,j,i+j,i+j+maxn(下标要是正的)表示,当cur等于枚举的答案maxd就判断是不是所有的标记都被攻击了。

    另外如果这个格子放上了皇后,那该皇后所在行的后边的格子就没必要枚举了,直接跳到下一行的开头就可以了。

    将二维数组线性表示的代码:

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define MAX 1e3
    #define FRE() freopen("in.txt","r",stdin)
    #define FRO() freopen("out.txt","w",stdout)
    using namespace std;
    typedef long long ll;
    const int maxn = 15;
    char mp[maxn][maxn];
    int vis[4][maxn*2];
    int n,m,maxd;
    
    bool isok(){//判断所有的标记是不是都已经被攻击
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                if(mp[i][j]=='X' && !vis[0][i] && !vis[1][j] && !vis[2][i+j] && !vis[3][i-j+maxn]){
                    return false;
                }
            }
        }
        return true;
    }
    
    bool dfs(int now, int cur){
        if(cur==maxd){
            return isok() ? true : false;
        }
    
        for(int k=now; k<n*m; k++){
            int i = k/n,j = k%m;
            vis[0][i]++; vis[1][j]++; vis[2][i+j]++; vis[3][i-j+maxn]++;//对四个方向进行标记
            if(dfs((i+1)*m,cur+1)){
                return true;
            }
            vis[0][i]--;vis[1][j]--;vis[2][i+j]--;vis[3][i-j+maxn]--;//恢复四个方向dfs之前的状态
        }
        return false;
    }
    
    int main(){
        //FRE();
        int kase = 0;
        while(scanf("%d",&n) && n){
            scanf("%d",&m);
            getchar();
            for(int i=0; i<n; i++){
                gets(mp[i]);
            }
            memset(vis,0,sizeof(vis));
            for(maxd = 0;; maxd++){
                if(dfs(0,0)){
                    break;
                }
            }
            printf("Case %d: %d
    ",++kase,maxd);
        }
        return 0;
    }

    正常二维数组表示代码:

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define MAX 1e3
    #define FRE() freopen("in.txt","r",stdin)
    #define FRO() freopen("out.txt","w",stdout)
    using namespace std;
    typedef long long ll;
    const int maxn = 15;
    char mp[maxn][maxn];
    int vis[4][maxn*2];
    int n,m,maxd;
    
    bool isok(){//判断所有的标记是不是都已经被攻击
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                if(mp[i][j]=='X' && !vis[0][i] && !vis[1][j] && !vis[2][i+j] && !vis[3][i-j+maxn]){
                    return false;
                }
            }
        }
        return true;
    }
    
    bool dfs(int x,int y, int cur){
        if(cur==maxd){
            return isok() ? true : false;
        }
    
        for(int i=x; i<n; i++){
            for(int j=y; j<m; j++){
                vis[0][i]++; vis[1][j]++; vis[2][i+j]++; vis[3][i-j+maxn]++;//对四个方向进行标记
                if(dfs(i+1,0,cur+1)){//这一行后边的都不用遍历了,直接跳到下一行的开头就可以了
                    return true;
                }
                vis[0][i]--;vis[1][j]--;vis[2][i+j]--;vis[3][i-j+maxn]--;//恢复四个方向dfs之前的状态
            }
        }
        return false;
    }
    
    int main(){
        //FRE();
        int kase = 0;
        while(scanf("%d",&n) && n){
            scanf("%d",&m);
            getchar();
            for(int i=0; i<n; i++){
                gets(mp[i]);
            }
    
            for(maxd = 0;; maxd++){
                memset(vis,0,sizeof(vis));
                if(dfs(0,0,0)){
                    break;
                }
            }
            printf("Case %d: %d
    ",++kase,maxd);
        }
        return 0;
    }
  • 相关阅读:
    互联网创业瞄准Web3.0时代 风投商造梦与毁梦 沧海
    SOA基础结构探究:服务调节与指挥 沧海
    排序算法小结 沧海
    上班触感 沧海
    经典程序摘录 沧海
    经典C程序100例 沧海
    ITIL进入快速增长期 2010年亚太市场将达$8亿 沧海
    必须要掌握的七种谈话技巧 沧海
    如何准备软件工程师的面试 沧海
    Junit教程 拂晓风起
  • 原文地址:https://www.cnblogs.com/sykline/p/10334815.html
Copyright © 2020-2023  润新知