[2012山东省第三届ACM大学生程序设计竞赛]——Mine Number

扫雷,开始想到是遍历,但一直想不出什么好的方法,看了学长的是深搜。。

#include <iostream>  
#include <string.h>  
using namespace std;  
#define MAX 25  
int n,m,num[MAX][MAX],dis[5][2]={0,0,1,0,-1,0,0,1,0,-1};  
char Map[MAX][MAX];  
bool ispos;  
// 判断出界  
bool isout(int x,int y)  
{  
    if( x<0 || y<0 || x>=n || y>=m )    return 1;  
    return 0;  
}  
// 判断五个点是否有小于等于0的位置  
bool location(int x,int y)  
{  
    int i,xx,yy;  
    for(i=0;i<5;++i)  
    {  
        xx=x+dis[i][0];  
        yy=y+dis[i][1];  
        if( !isout(xx,yy) && num[xx][yy]<=0 )   return false;  
    }  
    return true;  
}  
// 如果放雷,五个点数字减1  
void change(int x,int y)  
{  
    int i,xx,yy;  
    for(i=0;i<5;++i)  
    {  
        xx=x+dis[i][0];  
        yy=y+dis[i][1];  
        if( isout(xx,yy) )  continue;  
        --num[xx][yy];  
    }  
}  
// 如果该地原来放雷,但是应该不放,回溯,五个点数字加1  
void c_back(int x,int y)  
{  
    int i,xx,yy;  
    for(i=0;i<5;++i)  
    {  
        xx=x+dis[i][0];  
        yy=y+dis[i][1];  
        if( isout(xx,yy) )  continue;  
        ++num[xx][yy];  
    }  
}  
// 判断最后一行是否符合条件  
bool judge_final(void)  
{  
    int i;  
    for(i=0;i<m;++i)  
        if( num[n-1][i]!=0 )    return false;  
    return true;  
}  
// 输出结果  
void print(void)  
{  
    int i,j;  
    for(i=0;i<n;++i)  
    {  
        for(j=0;j<m;++j)  
            cout<<Map[i][j];  
        cout<<endl;  
    }  
}  
void dfs(int x,int y)  
{  
    if( ispos ) return;  
    if( x==n )  
    {  
        if( judge_final() )  
        {ispos=1;print();}  
        return;  
    }  
    if( y==m )  {dfs(x+1,0);return;}  
    if( x==0 )  // 首先第一行要进行枚举,不冲突即可  
    {  
        if( location(x,y) )  
        {  
            Map[x][y]='*';  
            change(x,y);  
            dfs(x,y+1);  
            c_back(x,y);  
        }  
        Map[x][y]='.';  
        dfs(x,y+1);  
    }  
    else// 其余行,根据上一行相应位置来判断如果做  
    {  
        if( num[x-1][y]==0 )    // 上一行为0,此行不能放雷  
        {  
            Map[x][y]='.';  
            dfs(x,y+1);  
        }  
        else if( num[x-1][y]==1 )   // 上一行为1,此行必须放雷,判断四周是否有0情况  
            if( location(x,y) )  
            {  
                Map[x][y]='*';  
                change(x,y);  
                dfs(x,y+1);  
                c_back(x,y);  
            }  
    }  
}  
  
int main()  
{  
    int i,j,test,t_num;  
    char c;  
    cin>>test;  
    for(t_num=1;t_num<=test;++t_num)  
    {  
        cin>>n>>m;  
        for(i=0;i<n;++i)  
            for(j=0;j<m;++j)  
            {  
                cin>>c;  
                num[i][j]=c-'0';  
            }  
        cout<<"Case "<<t_num<<":"<<endl;  
        ispos=0;  
        dfs(0,0);  
    }  
    return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值