241214 Ski Course Rating

Jongleee·2024년 12월 14일
0

TIL

목록 보기
756/786
public static void main(String[] args) throws IOException {
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	StringTokenizer st = new StringTokenizer(br.readLine());

	int rows = Integer.parseInt(st.nextToken());
	int cols = Integer.parseInt(st.nextToken());
	int threshold = Integer.parseInt(st.nextToken());

	int[][] grid = readGrid(br, rows, cols);
	boolean[][] startPoints = readStartPoints(br, rows, cols);
	int totalNodes = rows * cols;

	long result = calculateDifficulty(grid, startPoints, rows, cols, totalNodes, threshold);
	System.out.println(result);
}

private static int[][] readGrid(BufferedReader br, int rows, int cols) throws IOException {
	int[][] grid = new int[rows][cols];
	for (int i = 0; i < rows; i++) {
		StringTokenizer st = new StringTokenizer(br.readLine());
		for (int j = 0; j < cols; j++) {
			grid[i][j] = Integer.parseInt(st.nextToken());
		}
	}
	return grid;
}

private static boolean[][] readStartPoints(BufferedReader br, int rows, int cols) throws IOException {
	boolean[][] startPoints = new boolean[rows][cols];
	for (int i = 0; i < rows; i++) {
		StringTokenizer st = new StringTokenizer(br.readLine());
		for (int j = 0; j < cols; j++) {
			startPoints[i][j] = Integer.parseInt(st.nextToken()) == 1;
		}
	}
	return startPoints;
}

private static long calculateDifficulty(int[][] grid, boolean[][] startPoints, int rows, int cols, int totalNodes,
		int threshold) {
	PriorityQueue<Edge> edges = buildEdges(grid, rows, cols);
	UnionFind uf = new UnionFind(totalNodes);

	initializeStartPoints(startPoints, rows, cols, uf);

	long totalDifficulty = 0;

	while (!edges.isEmpty()) {
		Edge edge = edges.poll();
		int root1 = uf.find(edge.start);
		int root2 = uf.find(edge.end);

		if (root1 == root2)
			continue;

		uf.union(root1, root2);
		int newRoot = uf.find(edge.start);

		if (uf.getSize(newRoot) >= threshold && uf.getStartCount(newRoot) > 0) {
			totalDifficulty += (long) edge.weight * uf.getStartCount(newRoot);
			uf.resetStartCount(newRoot);
		}
	}

	return totalDifficulty;
}

private static PriorityQueue<Edge> buildEdges(int[][] grid, int rows, int cols) {
	PriorityQueue<Edge> edges = new PriorityQueue<>();
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			int startIdx = i * cols + j + 1;
			if (i < rows - 1) {
				int endIdx = (i + 1) * cols + j + 1;
				edges.add(new Edge(startIdx, endIdx, Math.abs(grid[i][j] - grid[i + 1][j])));
			}
			if (j < cols - 1) {
				int endIdx = i * cols + (j + 1) + 1;
				edges.add(new Edge(startIdx, endIdx, Math.abs(grid[i][j] - grid[i][j + 1])));
			}
		}
	}
	return edges;
}

private static void initializeStartPoints(boolean[][] startPoints, int rows, int cols, UnionFind uf) {
	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++) {
			if (startPoints[i][j]) {
				int idx = i * cols + j + 1;
				uf.incrementStartCount(idx);
			}
		}
	}
}

private static class Edge implements Comparable<Edge> {
	int start, end, weight;

	Edge(int start, int end, int weight) {
		this.start = start;
		this.end = end;
		this.weight = weight;
	}

	@Override
	public int compareTo(Edge other) {
		return Integer.compare(this.weight, other.weight);
	}
}

private static class UnionFind {
	private final int[] parent;
	private final int[] size;
	private final int[] startCount;

	public UnionFind(int totalNodes) {
		parent = new int[totalNodes + 1];
		size = new int[totalNodes + 1];
		startCount = new int[totalNodes + 1];

		for (int i = 1; i <= totalNodes; i++) {
			parent[i] = i;
			size[i] = 1;
		}
	}

	public int find(int node) {
		if (parent[node] != node) {
			parent[node] = find(parent[node]);
		}
		return parent[node];
	}

	public void union(int node1, int node2) {
		int root1 = find(node1);
		int root2 = find(node2);

		if (root1 == root2)
			return;

		if (size[root1] < size[root2]) {
			parent[root1] = root2;
			size[root2] += size[root1];
			startCount[root2] += startCount[root1];
		} else {
			parent[root2] = root1;
			size[root1] += size[root2];
			startCount[root1] += startCount[root2];
		}
	}

	public int getSize(int node) {
		return size[node];
	}

	public int getStartCount(int node) {
		return startCount[node];
	}

	public void incrementStartCount(int node) {
		startCount[node]++;
	}

	public void resetStartCount(int node) {
		startCount[node] = 0;
	}
}

출처:https://www.acmicpc.net/problem/9877

0개의 댓글