H Vin Diagram ICPC East Central NA 2016

题目链接:https://open.kattis.com/contests/ecva3o/problems/vindiagrams

Description: 

Problem H
Vin Diagrams

Venn diagrams were invented by the great logician John Venn as a way of categorizing elements belonging to different sets. Given two sets A and B, two overlapping circles are drawn – a circle representing the elements of A, and another representing the elements of B. The overlapping region of the circles represents element that belong to both A and B, i.e., the intersection of the two sets A∩B. A classic Venn diagram might look like this:

\includegraphics[width=0.3\textwidth ]{vin1}

Figure 1: Venn diagram of A∩B.

One of John’s biggest fans was his grandson, Vin Vaughn Venn. Vin was inspired by his grandfather’s diagrams, but Vin was a very creative individual. Simple overlapping circles struck Vin as too boring of a way to visualize the sometimes messy intersections of categories, so he set out to make his grandfather’s diagrams more interesting. Just like Venn diagrams, Vin diagrams are used as a way of categorizing elements belonging to different sets A and B, but the representation of each set is not required to be a circle. In fact, each set can have any shape as long as there is single overlapping section for elements in the intersection of A and B.

In this problem, Vin diagrams will be laid out on a grid. Each set representation is a loop of ‘X’ characters, with one ‘X’ in each loop replaced by an ‘A’ or ‘B’ to identify the loop. All empty positions (both inside and outside of the loops) are represented by period (‘.’) characters, and the set of positions inside a loop is contiguous. Each loop character touches exactly two other loop characters either vertically or horizontally. Loops do not self-intersect, and other than the allowed horizontal/vertical paths and right angle connections, different parts of the loop do not touch (see Figures 2 and 3 below).

\includegraphics[width=0.45\textwidth ]{vin2a}

Figure 2: Two legal loops

\includegraphics[width=0.45\textwidth ]{vin3a}

Figure 3: Two illegal loops

Loops A and B intersect at exactly two points. Loop intersection points always follow the pattern shown in Figure 4 (including the four ‘.’ positions around the intersection). No loop makes a right angle turn at an intersection point but always flows straight through the intersection, either vertically or horizontally. An example of legally intersecting loops is shown in Figure 5.

\includegraphics[width=0.15\textwidth ]{vin4}

Figure 4: Intersection point

\includegraphics[width=0.25\textwidth ]{vin5}

Figure 5: Legally intersecting loops surrounding positions

Input

The input starts with two integers r c describing the number of rows and columns in the Vin diagram (7≤r,c≤100). The following r rows each contain a string of c characters. All positions that are not part of loop Aor loop B are marked with a period (‘.’) character. The loop labels ‘A’ and ‘B’ are placed somewhere around the loops’ perimeters at non-intersection positions and are never on the same loop. The two loops will touch only at the two points where they intersect.

Output

Display, in order, the area of the Vin diagram exclusive to set A, the area exclusive to set B, and the area of the intersection. Given the representation of Vin diagrams, the area of a section is defined as the number of periods (‘.’) it encloses.

Sample Input 1Sample Output 1
7 7
AXXXX..
X...X..
X.XXXXX
X.X.X.X
XXXXX.X
..X...X
..XXXXB
5 5 1
Sample Input 2Sample Output 2
11 13
XXXXXXA......
X.....X......
X..XXXXXXXXX.
X..X..X....X.
X..X..XXX..XX
X..B....X...X
X..X.XXXX...X
X..X.X......X
XX.XXXXXX...X
.X...X..X.XXX
.XXXXX..XXX..
21 22 10

 

思路:知识点涉及到的主要是DFS染色。在初始化图的时候可以在最外围加一圈"."的边界,这样做可以排除在Loop A和Loop B之外的点。之后通过DFS来确定Loop A和Loop B的边界,注意假如color(row, col, dir, color)成功染色了的话,下一个染色的方向还是需要dir,假如没成功就换一个方向继续染色。最后数还没染色的(即被A、B包围起来)点 "." 的个数。

 


import java.util.Scanner;
public class VinDiagram {
	static int[][] visA;
	static int[][] visB;
	static char[][] g;
	static int r;
	static int c;
	static int[] dr = {1, -1, 0, 0};
	static int[] dc = {0, 0, 1, -1};
	public static void main(String args[]) {
		Scanner sc = new Scanner(System.in);
		//number of grids encompassed by A, B and the number of intersection 
		int countA, countB, countC;
		countA = countB = countC = 0;
		int ar, ac, br, bc;
		//the start position of DFS for A and B
		ar = ac = br = bc = -1;
		r = sc.nextInt();
		c = sc.nextInt();
		visA = new int[r + 2][c + 2];
		visB = new int[r + 2][c + 2];
		g = new char[r + 2][c + 2];
		//enclose the whole graph with the '.' boundary
		for (int i = 0; i < g.length; i++) {
			g[i][0] = '.';
			g[i][g[0].length - 1] = '.';
		}
		for (int i = 0; i < g[0].length; i++) {
			g[0][i] = '.';
			g[g.length - 1][i] = '.';
		}	
		//read input
		for (int i = 1; i <= r; i++) {
			char[] w = sc.next().toCharArray();
			for (int j = 1; j <= w.length; j++) {
				g[i][j] = w[j - 1];
				//determine the initial position of DFS for A and B
				if (w[j - 1] == 'A') {
					ar = i;
					ac = j;
				}
				if (w[j - 1] == 'B') {
					br = i;
					bc = j;
				}
			}
 		}
		sc.close();
		//color A
		colorA(ar, ac, 0, 1);
		//color B
		colorB(br, bc, 0, 2);
		//color the remaining
		dfs(0, 0, 6, visA);
		dfs(0, 0, 6, visB);
		//count the answer
		for (int i = 0; i < visA.length; i++) {
			for (int j = 0; j < visA[0].length; j++) {
				if (g[i][j] == '.' && visA[i][j] == 0) countA++;
				if (g[i][j] == '.' && visB[i][j] == 0) countB++;
				if (g[i][j] == '.' && visA[i][j] == 0 && visB[i][j] == 0) countC++;
			}
		}
		System.out.println((countA - countC) + " " + (countB - countC) + " " + countC);
	}
	private static boolean checkA(int i, int j) {
		if (i < 0 || j < 0 || i > g.length - 1 || j > g[0].length - 1) return false;
		if (visA[i][j] != 0) return false;
		return g[i][j] == 'X' || g[i][j] == 'A';
 	}
	private static void colorA(int i, int j, int dir, int color) {
		visA[i][j] = color;
		if (checkA(i + dr[dir], j + dc[dir])) {
			colorA(i + dr[dir], j + dc[dir], dir, color);
		} else {
			dfsA( i,  j,  color);
		}
	}
	private static void dfsA(int i, int j, int color) {
		if (checkA(i + 1, j)) {
			colorA(i, j, 0, color);
		} else if (checkA(i - 1, j)) {
			colorA(i, j, 1, color);
		} else if (checkA(i, j + 1)) {
			colorA(i, j, 2, color);
		} else if (checkA(i, j - 1)) {
			colorA(i, j, 3, color);
		}
	}
	private static boolean checkB(int i, int j) {
		if (i < 0 || j < 0 || i > g.length - 1 || j > g[0].length - 1) return false;
		if (visB[i][j] != 0) return false;
		return g[i][j] == 'X' || g[i][j] == 'B';
 	}
	private static void colorB(int i, int j, int dir, int color) {
		visB[i][j] = color;
		if (checkB(i + dr[dir], j + dc[dir])) {
			//notice that we can only proceed in one direction if succeed
			colorB(i + dr[dir], j + dc[dir], dir, color);
		} else {
			//switch position if this one does not work
			dfsB( i,  j,  color);
		}
	}
	private static void dfsB(int i, int j, int color) {
		if (checkB(i + 1, j)) {
			colorB(i, j, 0, color);
		} else if (checkB(i - 1, j)) {
			colorB(i, j, 1, color);
		} else if (checkB(i, j + 1)) {
			colorB(i, j, 2, color);
		} else if (checkB(i, j - 1)) {
			colorB(i, j, 3, color);
		}
	}
	private static void dfs(int i, int j, int color, int[][] vis) {
		for (int k = 0; k < 4; k++) {
			int row = i + dr[k];
			int col = j + dc[k];
			if (row < 0 || col < 0 || row > vis.length - 1 || col > vis[0].length - 1) continue;
			if (vis[row][col] != 0) continue;
			vis[row][col] = color;
			dfs(row, col, color, vis);
		}
	}
	
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值