2013山东省第三届ACM省赛 Mine Number

Mine Number

Time Limit: 1000MS Memory limit: 65536K

题目描述

Every one once played the game called Mine Sweeping, here I change the rule. You are given an n*m map, every element is a '*' representing a mine, or a '.' representing any other thing. If I ask you what's the total number of mines around (i, j), you should check (i, j)'s up, down, left, right and also itself (if overstep the boundary, ignore it), if that position is a '*', you should add one to the total number of (i, j), and here I call the number Mine Number. For example, if the map is "..**.. ", we can get the Mine Number as "012210" easily, but here is the question, if I give you the Mine Number, can you tell me the original map?

输入

The input consists of multiple test cases.
The first line contains a number T, representing the number of test cases.
Then T lines follow. For each case, the first line contains two numbers n and m (1<=n, m<=20).representing the lines and rows. Then following n lines, each line contain m numbers each number represents the Mine Number.

输出

For each case, please print the case number (beginning with 1) and the original map which you reverted. The data guarantee there is only one result.

示例输入

27 11100101001012122322122232354532323323555323233123532133321022201333100010001115 6001110013431014541013431001110

示例输出

Case 1:...........*..*.*..*.**.*****.*.**.*****.*.**..***..*.**...*...***...........Case 2:........***...***...***.......

提示

 

来源

2012年"浪潮杯"山东省第三届ACM大学生程序设计竞赛
题目链接:http://www.sdutacm.org/sdutoj/showproblem.php?pid=2410&cid=1744
题解链接:http://www.myexception.cn/program/1639575.html
#include <iostream>
#include <stdio.h>

using namespace std;

int a[25][25],n,m,flag;
char map[25][25];
int div[5][2]= {{0,0},{0,1},{0,-1},{1,0},{-1,0}};

int t_final()
{
    int i;
    for(i=0; i<m; i++)
        if(a[n-1][i]!=0)
            return 0;
    return 1;
}

void pri()
{
    int i,j;
    for(i=0; i<n; i++)
    {
        for(j=0; j<m; j++)
            printf("%c",map[i][j]);
        printf("\n");
    }
}

void change(int x,int y)//如果放雷,则周围5个位置的数字减1
{
    int i,xx,yy;
    for(i=0; i<5; i++)
    {
        xx=x+div[i][0];
        yy=y+div[i][1];
        if(xx<0 || yy<0 || xx>=n || yy>=m)
            continue;
        a[xx][yy]--;
    }
}

void back_change(int x,int y)//如果原来该位置放雷,现在回溯不再放雷,则周围5个位置的数字加1
{
    int i,xx,yy;
    for(i=0; i<5; i++)
    {
        xx=x+div[i][0];
        yy=y+div[i][1];
        if(xx<0 || yy<0 || xx>=n || yy>=m)
            continue;
        a[xx][yy]++;
    }
}

int locat(int x,int y)//判断周围5个位置是否有小于等于0的
{
    int i,xx,yy;
    for(i=0; i<5; i++)
    {
        xx=x+div[i][0];
        yy=y+div[i][1];
        if(!(xx<0 || yy<0 || xx>=n || yy>=m)&&a[xx][yy]<=0)
            return 0;
    }
    return 1;
}
void dfs(int x,int y)
{
    if(flag) return;
    if(x==n)
    {
        if(t_final())
        {
            flag=1;
            pri();
        }
         return;
    }
    if(y==m)
    {
        dfs(x+1,0);
        return;
    }
    if(x==0)//枚举第一行的情况
    {
        if(locat(x,y))
        {
            map[x][y]='*';
            change(x,y);
            dfs(x,y+1);
            back_change(x,y);
        }
        map[x][y]='.';
        dfs(x,y+1);
    }
    else //枚举其他行的情况,根据上一行相应位置的状态
    {
        if(a[x-1][y]==0)
        {
            map[x][y]='.';
            dfs(x,y+1);
        }
        else if(a[x-1][y]==1)
        {
            if(locat(x,y))
            {
                map[x][y]='*';
                change(x,y);
                dfs(x,y+1);
                back_change(x,y);//dfs之后回溯状态
            }
        }
    }

}

int main()
{
    int T,i,j,k;
    char c[25];
    scanf("%d",&T);

    for(k=1; k<=T; k++)
    {
        scanf("%d%d",&n,&m);
        getchar();
        for(i=0; i<n; i++)
           {
            gets(c);
            for(j=0; j<m; j++)
            {
                a[i][j]=c[j]-'0';
            }
           }
        printf("Case %d:\n",k);
        flag=0;
        dfs(0,0);
    }
    return 0;
}

你可能感兴趣的:(2013山东省第三届ACM省赛 Mine Number)