ZOJ 1002 Fire Net

题目如下:

大意:

假设现在有一个正方形的城市,里面有笔直的街道。一个城市的地图用一个正方形的板表示,板有n行n列,每行每列都代表着一条街道或者是一堵墙。

一个碉堡就是有四个可以进行射击的缺口的小城堡。这四个缺口分别面向东南西北四个方向。将有一个机枪通过每个缺口进行射击。

现在我们假设子弹是非常强大的,它可以穿过任意长的距离并且毁灭它所经过的一个碉堡。另一方面,一堵墙是足够强大的,它可以使子弹停下来。

我们的目标就是要在一个城市中尽可能多的安排碉堡并且任何两个碉堡不能互相攻击。如果说任何两个碉堡都不在同一行或者同一列,或者说两个碉堡在同一行或者同一列但是它们之间至少有一睹强将它们分开,那么这种碉堡的布局是合法的。在这个问题中我们考虑最多是4*4的小方城市,城市内有墙可以使子弹无法穿过。

下面的图片显示了五个相同板。第一张图片是空板,第二张和第三张图片显示了合法的布局。第四张和第五张图片显示了不合法的布局。对于这张板来说,合法布局中碉堡的最大个数就是5,第二张图片显示了其中的一种布局方式,但是还有其他的方式。


你的任务就是写一个程序,给你一个地图的描述,来计算一个城市合理布局中碉堡数目的最大值。

输入的文件包括一个或者多个地图的描述,接下来的一行如果是数组0就代表输入结束。每一个地图的描述的第一行是一个正整数n,代表城市的大小,n最大是4.接下来的n行,每一行都是对地图的每一行的描述。“."表示空地,大写的X表示一堵墙。输入文件中没有空格。

对于每一个测试案例,输出一行数据,表示这个城市合理布局中碉堡数目的最大值。


想法:

有点像八皇后的问题,用递归+回溯法。

想法就是从每一个可以放置碉堡的位置开始,先尝试放置,再判断,如果产生冲突就取消放置,如果不产生冲突然后就去下一个可放置的位置重复这个操作。

代码:

import java.util.Scanner;

public class Main {
	private static int count = 0;// 记录最多碉堡数
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
                while (n != 0) {
			char[][] ch = new char[n][n];
			int[][] vis = new int[n][n];
			int result = 0;
 			for (int i = 0; i < n; i++) {
 				String str = sc.next();
				for (int j = 0; j < n; j++) {
 					ch[i][j] = str.toCharArray()[j];
 					if (ch[i][j] == 'X') {
						vis[i][j] = 2;// 代表墙
					}
				}
			}
			for(int i = 0;i<n;i++){
 				for(int j = 0;j<n;j++){
					if(vis[i][j]==0){
						fun(n, vis, i, j);
						fun(n,vis,0,0);//一开始忘了这句,测试老不通过,郁闷的。。。
						if(count>result){
							result = count;
//							print(n, vis);
						}
						clear(vis);
						count = 0;
					}
				}
			}		
			System.out.println(result);
			n = sc.nextInt();
		}
	}

	private static void clear(int[][] vis) {
		int len = vis.length;
		for(int i = 0 ;i<len;i++){
			for(int j = 0;j<len;j++){
				if(vis[i][j]==1){
					vis[i][j]=0;
				}
			}
		}
	}

	private static void print(int n, int[][] vis) {
		for (int x = 0; x < n; x++) {
			for (int y = 0; y < n; y++) {
				System.out.print(vis[x][y] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	private static void fun(int n, int[][] vis, int i, int j) {
		if (vis[i][j] == 1 || vis[i][j] == 2) {
			if (j + 1 < n) {
				fun(n, vis, i, j + 1);
			} else if (i + 1 < n) {
				fun(n, vis, i + 1, 0);
			}
			return;
		} else {
			vis[i][j] = 1;// 代表i,j这个位置放置碉堡
			count++;
			if (isOk(vis,i,j)) {
				if (j + 1 < n) {
					fun(n, vis, i, j + 1);
				} else if (i + 1 < n) {
					fun(n, vis, i + 1, 0);
				}
			} else {
				vis[i][j] = 0;
				count--;
				if (j + 1 < n) {
					fun(n, vis, i, j + 1);
				} else if (i + 1 < n) {
					fun(n, vis, i + 1, 0);
				}
			}
		}
	}

	private static boolean isOk(int[][] vis, int i, int j) {
		int n = vis.length;
		for(int x = 0;x<n;x++){
			if(x!=j&&vis[i][x]==1){
				int from = j>x?x:j;
 				int to = j<x?x:j;
				boolean b =false;
				for(int y = from+1;y<to;y++){
					if(vis[i][y]==2){
						b = true;
						for(int z=from+1;z<y;z++){
							if(vis[i][z]==1){
								return false;
							}
						}
						for(int z=y;z<to;z++){
							if(vis[i][z]==1){
								return false;
							}
						}
					}
				}
				if(b==false){
					return false;
				}
			}else if(x!=i&&vis[x][j]==1){
				int from = i>x?x:i;
				int to = i<x?x:i;
				boolean b = false;
				for(int y=from+1;y<to;y++){
					if(vis[y][j]==2){
						b = true;
						for(int z =from+1;z<y;z++){
							if(vis[z][j]==1){
								return false;
							}
						}
						for(int z=y;z<to;z++){
							if(vis[z][j]==1){
								return false;
							}
						}
					}
				}
				if(b==false){
					return false;
				}
			}
		}
		return true;
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值