1. 문제
20303번: 할로윈의 양아치
첫째 줄에 정수 $N$, $M$, $K$가 주어진다. $N$은 거리에 있는 아이들의 수, $M$은 아이들의 친구 관계 수, $K$는 울음소리가 공명하기 위한 최소 아이의 수이다. ($1 \leq N \leq 30\ 000$, $0 \leq M \leq 100\ 000$,
www.acmicpc.net
2. 접근방법
0/1 KnapSack과 거기에 쓰일 집합들을 직접 구해 푸는 문제
처음 주어진 관계들에서 서로 연결된 요소들의 캔디양(value)과 사람수(weight)를 구한 뒤
0/1 KnapSack과 같이 DP로 문제를 해결하면 된다.
서로 연결된 요소를 구하는 방법엔 bfs, dfs, Union find 등이 있을 것 같은데
나는 직관적으로 떠오른 bfs를 사용했다.
3. 자바 코드
package Gold;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class G3_20303할라윈의양아치 {
static class group{
int candy;
int head;
public group(int candy, int head) {
this.candy = candy;
this.head = head;
}
}
static int candies[];
static ArrayList<group> groups = new ArrayList<group>();
static ArrayList<Integer> relation[];
static boolean visit[];
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()); //아이 수
int M = Integer.parseInt(st.nextToken()); //관계 수
int K = Integer.parseInt(st.nextToken()); //뺏는 수
relation = new ArrayList[N];
visit = new boolean[N];
for(int i = 0 ; i < N ; i++)
relation[i] = new ArrayList<Integer>();
candies = new int[N];
st = new StringTokenizer(br.readLine());
for(int i = 0 ; i < N ; i++)
candies[i] = Integer.parseInt(st.nextToken());
for(int i = 0 ; i < M ; i++) {
st = new StringTokenizer(br.readLine());
int to = Integer.parseInt(st.nextToken())-1;
int from = Integer.parseInt(st.nextToken())-1;
relation[to].add(from);
relation[from].add(to);
}
for(int i = 0 ; i < N ; i++) { //group 만들기
if(visit[i])
continue;
bfs(i);
}
int dp[][] = new int[2][K];
for(int i = 0 ; i < groups.size() ; i++) {
group now = groups.get(i);
int head = now.head;
int candy = now.candy;
for(int j = 0 ; j < K ; j++) {
if(j>=head && dp[0][j-head]+candy > dp[0][j])
dp[1][j] =dp[0][j-head]+candy;
else
dp[1][j] = dp[0][j];
}
dp[0] = dp[1].clone();
}
System.out.println(dp[1][K-1]);
}
static void bfs(int start) {
visit[start] = true;
Queue<Integer> que = new LinkedList<Integer>();
que.offer(start);
int head = 1,candy = candies[start];
while(!que.isEmpty()) {
int now = que.poll();
for(int i : relation[now]) {
if(visit[i])
continue;
visit[i] = true;
que.offer(i);
head++;
candy += candies[i];
}
}
groups.add(new group(candy,head));
}
}
4. 마치며
두가지 개념이 섞여서 그렇지
그렇게 어렵진 않게 해결한 문제이다.
'알고리즘 문제풀이 > 백준' 카테고리의 다른 글
[백준] 2457 공주님의 정원 (0) | 2020.12.17 |
---|---|
[백준] 16287 Parcel (0) | 2020.12.15 |
[백준] 20209 스트레이트 스위치 게임 (부분집합) (0) | 2020.12.05 |
[백준] 20209 스트레이트 스위치 게임(BFS) (0) | 2020.12.03 |
[백준] 20159 동작 그만 밑장 빼기냐 (0) | 2020.12.03 |