杭电1045 Fire Net(dfs过)(图搜)

Fire Net

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8703    Accepted Submission(s): 5024


Problem Description
Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall. 

A blockhouse is a small castle that has four openings through which to shoot. The four openings are facing North, East, South, and West, respectively. There will be one machine gun shooting through each opening. 

Here we assume that a bullet is so powerful that it can run across any distance and destroy a blockhouse on its way. On the other hand, a wall is so strongly built that can stop the bullets. 

The goal is to place as many blockhouses in a city as possible so that no two can destroy each other. A configuration of blockhouses is legal provided that no two blockhouses are on the same horizontal row or vertical column in a map unless there is at least one wall separating them. In this problem we will consider small square cities (at most 4x4) that contain walls through which bullets cannot run through. 

The following image shows five pictures of the same board. The first picture is the empty board, the second and third pictures show legal configurations, and the fourth and fifth pictures show illegal configurations. For this board, the maximum number of blockhouses in a legal configuration is 5; the second picture shows one way to do it, but there are several other ways. 



Your task is to write a program that, given a description of a map, calculates the maximum number of blockhouses that can be placed in the city in a legal configuration. 
 

Input
The input file contains one or more map descriptions, followed by a line containing the number 0 that signals the end of the file. Each map description begins with a line containing a positive integer n that is the size of the city; n will be at most 4. The next n lines each describe one row of the map, with a '.' indicating an open space and an uppercase 'X' indicating a wall. There are no spaces in the input file. 
 

Output
For each test case, output one line containing the maximum number of blockhouses that can be placed in the city in a legal configuration.
 

Sample Input
  
  
4 .X.. .... XX.. .... 2 XX .X 3 .X. X.X .X. 3 ... .XX .XX 4 .... .... .... .... 0
 

Sample Output
  
  
5 1 5 2 4

类似于n皇后的问题类型,要有回溯的思想。

这里很简单能想到的问题就是行和列的判断的问题,如果行或列上边有炮就不行,但是如果有墙隔开就不一样了:

int  panduan(int x,int y)
{
    for(int i=x-1;i>=0;i--)
    {
        if(a[i][y]=='0')//我这里标记大炮的字符为0;
        return 0;
        if(a[i][y]=='X')//如果遇到了墙,就直接break就行
        break;
    }
    for(int i=y-1;i>=0;i--)
    {
        if(a[x][i]=='0')
        return 0;
        if(a[x][i]=='X')
        break;
    }
    return 1;
}
那么,深搜的起点和终点呢?起点是(0,0)终点是(n-1,n-1),首先我们知道,满足条件的可能是有多种的,我们要最优的解,所以要有一个动态变量 sum表示本次深搜尝试的当前大炮数,和一个最终输出变量output。

那么要如何进行搜索的步骤呢?我们从起点出发,每一个点都遍历。每一个点都尝试一下放大炮和不放大炮,所以我们这里无非两种走法:1.按上大炮向下一个格子移动,2.不按大炮向下一个格子移动。然后上代码的核心部分对应详解:

void dfs(int k,int sum)//sum代表当前大炮数量
{
    int x,y;
    if(k==n*n)//如果深搜走到了终点
    {
        if(sum>output)//判断当前这种情况是否能比最终解output大。
        {
            output=sum;
            return ;
        }
    }
    else
    {
        x=k/n;
        y=k%n;
        if(a[x][y]=='.'&&panduan(x,y))//如果当前的点可以放置大炮,并且放置大炮合法的情况下
        {
            a[x][y]='0';//我们放置上大炮
            dfs(k+1,sum+1);//并且进入下一个格子
            a[x][y]='.';//千万记住这里要改回来,因为这个点也有不放置大炮的权利,我们在下一个点深搜的时候有着地图0标记,但是要进行另一种情况的时候不能带着地图0标记了。
        }
        ///
        dfs(k+1,sum);//这里表示墙或者是不按大炮的向下一个格子的深搜
    }
}
最后上完整的AC代码:

#include<stdio.h>
#include<string.h>
using namespace std;
char a[10][10];
int n;
int output;
int  panduan(int x,int y)
{
    for(int i=x-1;i>=0;i--)
    {
        if(a[i][y]=='0')
        return 0;
        if(a[i][y]=='X')
        break;
    }
    for(int i=y-1;i>=0;i--)
    {
        if(a[x][i]=='0')
        return 0;
        if(a[x][i]=='X')
        break;
    }
    return 1;
}
void dfs(int k,int sum)
{
    int x,y;
    if(k==n*n)
    {
        if(sum>output)
        {
            output=sum;
            return ;
        }
    }
    else
    {
        x=k/n;
        y=k%n;
        if(a[x][y]=='.'&&panduan(x,y))
        {
            a[x][y]='0';
            dfs(k+1,sum+1);
            a[x][y]='.';
        }
        ///
        dfs(k+1,sum);
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        if(n==0)break;
        for(int i=0;i<n;i++)
        {
            scanf("%s",a[i]);
        }
        output=0;
        dfs(0,0);
        printf("%d\n",output);
    }
}








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值