알고리즘/BOJ

17472. 다리 만들기 2

병인 2019. 10. 16. 20:04

https://www.acmicpc.net/problem/17472

 

17472번: 다리 만들기 2

첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 지도의 정보가 주어진다. 각 줄은 M개의 수로 이루어져 있으며, 수는 0 또는 1이다. 0은 바다, 1은 땅을 의미한다.

www.acmicpc.net

마지막에 최소 스패닝 트리에 모든 섬이 포함되었는지 확인하는걸 빼먹어서 오답이 많이 났었다.

<JAVA>

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;

class pos {
	pos(int x, int y) {
		this.x = x;
		this.y = y;
	}

	int x, y;
}

class bridge implements Comparable<bridge> {
	int from, to, count;

	bridge(int from, int to, int count) {
		this.from = from;
		this.to = to;
		this.count = count;
	}

	@Override
	public int compareTo(bridge o) {
		return Integer.compare(count, o.count);
	}
};

class Main {

	static final int dx[] = { 1, -1, 0, 0 };
	static final int dy[] = { 0, 0, 1, -1 };
	static int N, M;
	static int map[][] = new int[10][10];
	static boolean visit[][] = new boolean[10][10];
	static int relation[] = new int[10];
	static int unionCnt = 0;
	static int islandCnt = 0;
	static int result = 0;
	static List<bridge> list = new ArrayList<>();

	static int find(int n) {
		if (relation[n] == n)
			return n;
		else
			return relation[n] = find(relation[n]);
	}

	static void _union(int x, int y, int idx) {
		x -= 2;
		y -= 2;
		x = find(x);
		y = find(y);
		if (x == y)
			return;
		relation[x] = y;
		++unionCnt;
		result += list.get(idx).count;
	}

	static void input() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		for (int i = 0; i < N; ++i) {
			st = new StringTokenizer(br.readLine(), " ");
			for (int j = 0; j < M; ++j) {
				map[i][j] = Integer.parseInt(st.nextToken(" "));
			}
		}
	}

	static void islandSetting() {
		for (int i = 0; i < 10; ++i) {
			relation[i] = i;
		}
		int index = 2;
		Queue<pos> q = new LinkedList<>();
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < M; ++j) {
				if (!visit[i][j] && map[i][j] == 1) {
					visit[i][j] = true;
					map[i][j] = index;
					q.add(new pos(i, j));
					while (!q.isEmpty()) {
						pos cur = q.poll();
						for (int dir = 0; dir < 4; ++dir) {
							int nx = cur.x + dx[dir];
							int ny = cur.y + dy[dir];
							if (nx < 0 || ny < 0 || nx >= N || ny >= M || visit[nx][ny] || map[nx][ny] != 1) {
								continue;
							}
							q.add(new pos(nx, ny));
							map[nx][ny] = index;
							visit[nx][ny] = true;
						}
					}
					++index; // 섬의 번호 증가
				}
			}
		}
		islandCnt = index - 2;
	}

	static void searchBridge() {
		int index = 0;
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < M; ++j) {
				if (map[i][j] != 0) {
					index = map[i][j];
					for (int dir = 0; dir < 4; ++dir) {
						int nx = i;
						int ny = j;
						int cnt = 0;
						while (true) {
							nx += dx[dir];
							ny += dy[dir];
							if (nx < 0 || ny < 0 || nx >= N || ny >= M) {
								break;
							}
							if (map[nx][ny] != 0) {
								if (map[nx][ny] != index && cnt > 1) {
									list.add(new bridge(index, map[nx][ny], cnt));
								}
								break;
							}
							++cnt;
						}
					}
				}
			}
		}
	}

	static void makeBridge() {
		Collections.sort(list);
		for (int i = 0; i < list.size(); ++i) {
			_union(list.get(i).from, list.get(i).to, i);
			if (islandCnt == unionCnt)
				break;
		}
	}

	public static void main(String[] args) throws Exception {
		unionCnt = 0;
		result = 0;
		input();
		islandSetting();
		searchBridge();
		makeBridge();
		// 최소 스패닝 트리에 모든 섬이 포함되었는지 확인
		int f = find(0);
		for (int i = 1; i < islandCnt; i++) {
			if (f != find(i)) {
				result = 0;
			}
		}

		if (result == 0)
			System.out.println("-1");
		else
			System.out.println(result);
	}
}

<C++>

#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;

struct pos
{
	int x, y;
};
struct bridge
{
	int from, to, count;
	bool operator < (bridge b)
	{
		return count < b.count;
	}
};
const int dx[] = { 1, -1, 0, 0 };
const int dy[] = { 0, 0, 1, -1 };
int N, M;
int map[10][10];
bool visit[10][10];
int relation[10];
int unionCnt = 0;
int islandCnt = 0;
int result = 0;
vector<bridge> v;

int find(int n) {
	if (relation[n] == n)
		return n;
	else
		return relation[n] = find(relation[n]);
}
void _union(int x, int y, int idx) {
	x -= 2;
	y -= 2;
	x = find(x);
	y = find(y);
	if (x == y)
		return;
	relation[x] = y;
	++unionCnt;
	result += v[idx].count;
}
void input()
{
	cin >> N >> M;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < M; ++j)
		{
			cin >> map[i][j];
		}
	}
}
void islandSetting()
{
	for (int i = 0; i < 10; ++i)
	{
		relation[i] = i;
	}

	int index = 2;
	memset(visit, false, sizeof(visit));
	queue<pos> q;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < M; ++j)
		{
			if (!visit[i][j] && map[i][j] == 1)
			{
				visit[i][j] = true;
				map[i][j] = index;
				q.push({ i,j });
				while (!q.empty())
				{
					pos cur = q.front(); q.pop();
					for (int dir = 0; dir < 4; ++dir)
					{
						int nx = cur.x + dx[dir];
						int ny = cur.y + dy[dir];
						if (nx < 0 || ny < 0 || nx >= N || ny >= M || visit[nx][ny] || map[nx][ny] != 1)
						{
							continue;
						}
						q.push({ nx,ny });
						map[nx][ny] = index;
						visit[nx][ny] = true;
					}
				}
				++index;	//섬의 번호 증가
			}
		}
	}
	islandCnt = index - 2;
}
void searchBridge()
{
	int index = 0;
	for (int i = 0; i < N; ++i)
	{
		for (int j = 0; j < M; ++j)
		{
			if (map[i][j] != 0)
			{
				index = map[i][j];
				for (int dir = 0; dir < 4; ++dir)
				{
					int nx = i;
					int ny = j;
					int cnt = 0;
					while (true)
					{
						nx += dx[dir];
						ny += dy[dir];
						if (nx < 0 || ny < 0 || nx >= N || ny >= M)
						{
							break;
						}
						if (map[nx][ny] != 0)
						{
							if (map[nx][ny] != index && cnt > 1)
							{
								v.push_back({ index,map[nx][ny],cnt });
							}
							break;
						}
						++cnt;
					}
				}
			}
		}
	}
}
void makeBridge()
{
	sort(v.begin(), v.end());
	for (int i = 0; i < v.size(); ++i)
	{
		_union(v[i].from, v[i].to, i);
		if (islandCnt == unionCnt)
			break;
	}
}
int main()
{
	cin.tie(NULL); cout.tie(NULL); ios_base::sync_with_stdio(false);
	unionCnt = 0;
	result = 0;
	input();
	islandSetting();
	searchBridge();
	makeBridge();
	// 최소 스패닝 트리에 모든 섬이 포함되었는지 확인
	int f = find(0);
	for (int i = 1; i < islandCnt; i++)
	{
		if (f != find(i))
		{
			result = 0;
		}
	}

	if (result == 0)
		cout << -1;
	else
		cout << result;
	return 0;
}