ACM HDOJ 1045 (Fire Net)

24 篇文章 0 订阅
7 篇文章 0 订阅

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1045

思路一 深度优先搜索

这个应该最容易想到了,从左上开始,按列搜索,到右下结束,具体的搜索顺序如下图


思路二 二分图的最大匹配

 一行拆成多行,一列拆成多列
 以下图为例
.X..
 ....
XX..
....

按行排号(左集)
1X22
3333
XX44
5555
 
按列排号(右集)
1X56
1356
XX56
2456

找到左集和右集中有交叉的情况
左 -> 右
1 -> 1
2 -> 5
2 -> 6
3 -> 1
3 -> 3
3 -> 5
3 -> 6
4 -> 5
4 -> 6
5 -> 2
5 -> 4
5 -> 5
5 -> 6

然后二分匹配,得到最大匹配为
1 -> 1
2 -> 5
3 -> 3
4 -> 6
5 -> 2

则放置碉堡的结果就是
OXO.
.O..
XX.O
O...

程序一 深度优先搜索

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = height;
			if (0 == height) {
				break;
			}
			Search search = new Search(height, width, 0, 0);
			for (int i = 0; i < height; ++i) {
				search.setMatrixLine(i, scn.next().toCharArray());
			}
			search.beginSearch();
			System.out.println(search.getMaxNumber());
		}
		scn.close();
	}

}

class Search {

	private int height;
	private int width;
	private char[][] matrix;
	private int startX;
	private int startY;
	private int maxNumber;

	public Search(int height, int width, int startX, int startY) {
		this.height = height;
		this.width = width;
		matrix = new char[height][width];
		this.startX = startX;
		this.startY = startY;
		maxNumber = 0;
	}

	public void beginSearch() {
		dfs(startX, startY, 0);
	}

	private void dfs(int x, int y, int number) {
		if (x == height - 1 && y == width - 1) {
			if ('.' == matrix[x][y] && isValid(x, y)) {
				++number;
			}
			if (number > maxNumber) {
				maxNumber = number;
			}
			return;
		}
		if ('X' == matrix[x][y] || !isValid(x, y)) {
			if (y < width - 1) {
				dfs(x, y + 1, number);
			} else {
				dfs(x + 1, 0, number);
			}
		} else {
			matrix[x][y] = '*';
			if (y < width - 1) {
				dfs(x, y + 1, number + 1);
			} else {
				dfs(x + 1, 0, number + 1);
			}
			matrix[x][y] = '.';
			if (y < width - 1) {
				dfs(x, y + 1, number);
			} else {
				dfs(x + 1, 0, number);
			}
		}
		return;
	}

	private boolean isValid(int x, int y) {
		for (int i = x - 1; i >= 0; --i) {
			if ('X' == matrix[i][y]) {
				break;
			}
			if ('*' == matrix[i][y]) {
				return false;
			}
		}
		for (int j = y - 1; j >= 0; --j) {
			if ('X' == matrix[x][j]) {
				break;
			}
			if ('*' == matrix[x][j]) {
				return false;
			}
		}
		return true;
	}

	public void setMatrixLine(int line, char[] ch) {
		matrix[line] = ch;
	}

	public int getMaxNumber() {
		return maxNumber;
	}

}

程序二 匈牙利算法 DFS

import java.util.Arrays;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = height;
			if (0 == height) {
				break;
			}
			char[][] city = new char[height][width];
			int[][] left = new int[height][width];
			for (int i = 0; i < height; ++i) {
				city[i] = scn.next().toCharArray();
			}
			int leftSetNumber = 0;
			for (int i = 0; i < height; ++i) { // 按行
				if ('.' == city[i][0]) {
					left[i][0] = ++leftSetNumber;
				} else {
					++leftSetNumber;
				}
				boolean flag = true;
				for (int j = 1; j < width; ++j) {
					if ('.' == city[i][j]) {
						if (flag) {
							left[i][j] = leftSetNumber;
						} else {
							left[i][j] = ++leftSetNumber;
							flag = true;
						}
					} else {
						flag = false;
					}
				}
			}
			int rightSetNumber = 0;
			int[][] right = new int[height][width];
			for (int j = 0; j < height; ++j) { // 按列
				if ('.' == city[0][j]) {
					right[0][j] = ++rightSetNumber;
				} else {
					++rightSetNumber;
				}
				boolean flag = true;
				for (int i = 1; i < width; ++i) {
					if ('.' == city[i][j]) {
						if (flag) {
							right[i][j] = rightSetNumber;
						} else {
							right[i][j] = ++rightSetNumber;
							flag = true;
						}
					} else {
						flag = false;
					}
				}
			}
			Hungary hungary = new Hungary(leftSetNumber, rightSetNumber);
			for (int i = 0; i < height; ++i) {
				for (int j = 0; j < width; ++j) {
					if (0 != left[i][j] && 0 != right[i][j]) {
						hungary.addEdge(left[i][j] - 1, right[i][j] - 1);
					}
				}
			}
			System.out.println(hungary.maxMatch());
		}
		scn.close();
	}

}

class Hungary {

	private int leftSetNumber;
	private int rightSetNumber;
	private boolean[][] matrix;
	private int[] leftResult;
	private int[] rightResult;
	private boolean[] rightUsed;

	private boolean searchPath(int left) {
		for (int right = 0; right < rightSetNumber; ++right) {
			if (matrix[left][right] && !rightUsed[right]) {
				rightUsed[right] = true;
				if (-1 == rightResult[right] || searchPath(rightResult[right])) {
					rightResult[right] = left;
					leftResult[left] = right;
					return true;
				}
			}
		}
		return false;
	}

	public Hungary(int leftSetNumber, int rightSetNumber) {
		this.leftSetNumber = leftSetNumber;
		this.rightSetNumber = rightSetNumber;
		matrix = new boolean[leftSetNumber][rightSetNumber];
		leftResult = new int[leftSetNumber];
		rightResult = new int[rightSetNumber];
		rightUsed = new boolean[rightSetNumber];
	}

	public void addEdge(int left, int right) {
		matrix[left][right] = true;
	}

	public int maxMatch() {
		Arrays.fill(leftResult, -1);
		Arrays.fill(rightResult, -1);
		Arrays.fill(rightUsed, false);
		int count = 0;
		for (int left = 0; left < leftSetNumber; ++left) {
			if (-1 == leftResult[left]) {
				Arrays.fill(rightUsed, false);
				if (searchPath(left)) {
					++count;
				}
			}
		}
		return count;
	}

}

程序三 匈牙利算法 BFS

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = height;
			if (0 == height) {
				break;
			}
			char[][] city = new char[height][width];
			int[][] left = new int[height][width];
			for (int i = 0; i < height; ++i) {
				city[i] = scn.next().toCharArray();
			}
			int leftSetNumber = 0;
			for (int i = 0; i < height; ++i) { // 按行
				if ('.' == city[i][0]) {
					left[i][0] = ++leftSetNumber;
				} else {
					++leftSetNumber;
				}
				boolean flag = true;
				for (int j = 1; j < width; ++j) {
					if ('.' == city[i][j]) {
						if (flag) {
							left[i][j] = leftSetNumber;
						} else {
							left[i][j] = ++leftSetNumber;
							flag = true;
						}
					} else {
						flag = false;
					}
				}
			}
			int rightSetNumber = 0;
			int[][] right = new int[height][width];
			for (int j = 0; j < height; ++j) { // 按列
				if ('.' == city[0][j]) {
					right[0][j] = ++rightSetNumber;
				} else {
					++rightSetNumber;
				}
				boolean flag = true;
				for (int i = 1; i < width; ++i) {
					if ('.' == city[i][j]) {
						if (flag) {
							right[i][j] = rightSetNumber;
						} else {
							right[i][j] = ++rightSetNumber;
							flag = true;
						}
					} else {
						flag = false;
					}
				}
			}
			Hungary hungary = new Hungary(leftSetNumber, rightSetNumber);
			for (int i = 0; i < height; ++i) {
				for (int j = 0; j < width; ++j) {
					if (0 != left[i][j] && 0 != right[i][j]) {
						hungary.addEdge(left[i][j] - 1, right[i][j] - 1);
					}
				}
			}
			System.out.println(hungary.maxMatch());
		}
		scn.close();
	}

}

class Hungary {

	private int leftSetNumber;
	private int rightSetNumber;
	private boolean[][] matrix;
	private int[] leftResult;
	private int[] rightResult;
	private boolean[] rightUsed;
	private int[] preLeft;

	public Hungary(int leftSetNumber, int rightSetNumber) {
		this.leftSetNumber = leftSetNumber;
		this.rightSetNumber = rightSetNumber;
		matrix = new boolean[leftSetNumber][rightSetNumber];
		leftResult = new int[leftSetNumber];
		rightResult = new int[rightSetNumber];
		rightUsed = new boolean[rightSetNumber];
		preLeft = new int[leftSetNumber];
	}

	public void addEdge(int left, int right) {
		matrix[left][right] = true;
	}

	public int maxMatch() {
		Arrays.fill(leftResult, -1);
		Arrays.fill(rightResult, -1);
		Arrays.fill(preLeft, -1);
		int count = 0;
		for (int i = 0; i < leftSetNumber; ++i) {
			if (-1 == leftResult[i]) {
				Queue<Integer> queue = new LinkedList<Integer>();
				queue.offer(i);
				boolean hasAP = false;
				Arrays.fill(rightUsed, false);
				while (!queue.isEmpty() && !hasAP) {
					int left = queue.poll();
					for (int right = 0; right < rightSetNumber && !hasAP; ++right) {
						if (matrix[left][right] && !rightUsed[right]) {
							rightUsed[right] = true;
							queue.offer(rightResult[right]);
							if (0 <= rightResult[right]) {
								preLeft[rightResult[right]] = left;
							} else {
								hasAP = true;
								int currentLeft = left;
								int currentRight = right;
								while (-1 != currentLeft) {
									int lastRight = leftResult[currentLeft];
									leftResult[currentLeft] = currentRight;
									rightResult[currentRight] = currentLeft;
									currentLeft = preLeft[currentLeft];
									currentRight = lastRight;
								}
							}
						}
					}
				}
				if (-1 != leftResult[i]) {
					++count;
				}
			}
		}
		return count;
	}

}

程序四 Hopcroft-Carp 算法

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner scn = new Scanner(System.in);
		while (scn.hasNext()) {
			int height = Integer.parseInt(scn.next());
			int width = height;
			if (0 == height) {
				break;
			}
			char[][] city = new char[height][width];
			int[][] left = new int[height][width];
			for (int i = 0; i < height; ++i) {
				city[i] = scn.next().toCharArray();
			}
			int leftSetNumber = 0;
			for (int i = 0; i < height; ++i) { // 按行
				if ('.' == city[i][0]) {
					left[i][0] = ++leftSetNumber;
				} else {
					++leftSetNumber;
				}
				boolean flag = true;
				for (int j = 1; j < width; ++j) {
					if ('.' == city[i][j]) {
						if (flag) {
							left[i][j] = leftSetNumber;
						} else {
							left[i][j] = ++leftSetNumber;
							flag = true;
						}
					} else {
						flag = false;
					}
				}
			}
			int rightSetNumber = 0;
			int[][] right = new int[height][width];
			for (int j = 0; j < height; ++j) { // 按列
				if ('.' == city[0][j]) {
					right[0][j] = ++rightSetNumber;
				} else {
					++rightSetNumber;
				}
				boolean flag = true;
				for (int i = 1; i < width; ++i) {
					if ('.' == city[i][j]) {
						if (flag) {
							right[i][j] = rightSetNumber;
						} else {
							right[i][j] = ++rightSetNumber;
							flag = true;
						}
					} else {
						flag = false;
					}
				}
			}
			HopcroftCarp hopcroftCarp = new HopcroftCarp(leftSetNumber,
					rightSetNumber);
			for (int i = 0; i < height; ++i) {
				for (int j = 0; j < width; ++j) {
					if (0 != left[i][j] && 0 != right[i][j]) {
						hopcroftCarp.addEdge(left[i][j] - 1, right[i][j] - 1);
					}
				}
			}
			System.out.println(hopcroftCarp.maxMatch());
		}
		scn.close();
	}

}

class HopcroftCarp {

	private final int INF = Integer.MAX_VALUE / 2;
	private int leftSetNumber;
	private int rightSetNumber;
	private boolean[][] matrix;
	private int[] leftResult;
	private int[] rightResult;
	private boolean[] rightUsed;
	private int[] leftGradation;
	private int[] rightGradation;
	private int gradation;

	private boolean searchPath() {
		Arrays.fill(leftGradation, -1);
		Arrays.fill(rightGradation, -1);
		gradation = INF;
		Queue<Integer> queue = new LinkedList<Integer>();
		for (int left = 0; left < leftSetNumber; ++left) {
			if (-1 == leftResult[left]) {
				queue.offer(left);
				++leftGradation[left];
			}
		}
		while (!queue.isEmpty()) {
			int left = queue.poll();
			if (leftGradation[left] > gradation) {
				break;
			}
			for (int right = 0; right < rightSetNumber; ++right) {
				if (matrix[left][right] && -1 == rightGradation[right]) {
					rightGradation[right] = leftGradation[left] + 1;
					if (-1 == rightResult[right]) {
						gradation = rightGradation[right];
					} else {
						leftGradation[rightResult[right]] = rightGradation[right] + 1;
						queue.offer(rightResult[right]);
					}
				}
			}
		}
		return INF != gradation;
	}

	private boolean dfs(int left) {
		for (int right = 0; right < rightSetNumber; right++) {
			if (!rightUsed[right] && matrix[left][right]
					&& rightGradation[right] == leftGradation[left] + 1) {
				rightUsed[right] = true;
				if (-1 != rightResult[right]
						&& rightGradation[right] == gradation) {
					continue;
				}
				if (-1 == rightResult[right] || dfs(rightResult[right])) {
					rightResult[right] = left;
					leftResult[left] = right;
					return true;
				}
			}
		}
		return false;
	}

	public HopcroftCarp(int leftSetNumber, int rightSetNumber) {
		this.leftSetNumber = leftSetNumber;
		this.rightSetNumber = rightSetNumber;
		matrix = new boolean[leftSetNumber][rightSetNumber];
		leftResult = new int[leftSetNumber];
		rightResult = new int[rightSetNumber];
		rightUsed = new boolean[rightSetNumber];
		leftGradation = new int[leftSetNumber];
		rightGradation = new int[rightSetNumber];
		gradation = INF;
	}

	public void addEdge(int left, int right) {
		matrix[left][right] = true;
	}

	public int maxMatch() {
		Arrays.fill(leftResult, -1);
		Arrays.fill(rightResult, -1);
		int count = 0;
		while (searchPath()) {
			Arrays.fill(rightUsed, false);
			for (int left = 0; left < leftSetNumber; ++left) {
				if (-1 == leftResult[left] && dfs(left)) {
					++count;
				}
			}
		}
		return count;
	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值