https://www.acmicpc.net/problem/1007
1007번: 벡터 매칭
평면 상에 N개의 점이 찍혀있고, 그 점을 집합 P라고 하자. 집합 P의 벡터 매칭은 벡터의 집합인데, 모든 벡터는 집합 P의 한 점에서 시작해서, 또 다른 점에서 끝나는 벡터의 집합이다. 또, P에 속
www.acmicpc.net
1. 문제 유형과 이해
완전 탐색
평면 상에 N 개의 점이 찍혀있고 그 점들의 집합을 집합 P라고 하자.
집합P의 벡터 매칭은 벡터의 집합인데,
집합 P의 한점에서 시작해서 다른 점에서 끝나는 집합이고, P에 속하는 모든 점은 한번 씩 쓰여야한다.
벡터 매칭의 벡터의 합의 길이의 최소값을 구하시오.
두 점 (a,b)와 (c,d)의 벡터는
(a-c, b-d)가 된다. 이러한 벡터들의 집합이 벡터 매칭이 된다.
이 벡터 매칭에서 이 벡터들끼리 합하여 나온 벡터의 합의 길이 최소 값을 구하면 된다.
즉, 시작점 N/2개와 끝점 N/2개로 이루어져 있기 때문에 우리는 N/2개를 선택해주면되는데, 이 때
문제 조건에서 N은 20보다 작거나 같은 자연수이므로 구할 수 있는 최대 가짓 수는 $_20C_10$로 충분히 가능하다.
2. 문제 접근 방법
주어진 N개의 점 중 끝점들을 빼주면된다.
N개의 점을 골라서 빼주면 되는데 이 때
1. N 개의 점을 고르기 -> 백준 N과 K 문제처럼 생각하면 된다.
중복을 허용하지 않고 N개 중 N/2개를 고르기라고 생각하고 큰 구조를 짠다.
2. 점을 빼주기
더해가면서 해당 select되는 점을 빼주는 방식 한가지 또는
미리 다 더해놓고 해당 select되는점을 2번 빼주면 한 번 빼준 것과 마찬가지인 방식 한가지.
시간 상으로 미리 다 더해놓고 빼주는 것이 빠르다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
/**
* @문제번호 : Q1007
* @문제이름 : 벡터 매칭
* @난이도 : GoldII
* @date : 2022-02-12 오전 7:59
* @author : pcrmcw0486
* @문제이해
* 평면상 N개의 점 그 점 집합을 P
* P의 벡터 매칭은 벡터의 집합 벡터는 P의 한점에서 다른 점으로 끝나는 벡터의 집합
* P에 속하는 모든 점은 한번씩 쓰여야한다.
* 벡터 매칭에 있는 벡터 개수는 P점의 절반이다.
* 벡터 매칭의 벡터 합 길이 최소값
* @알고리즘
* 모든 조합을 보는 것은 너무 많은 경우의 수이다.
* 벡터 합의 길이가 최소가 되려면,
* @접근방법
*/
public class Main {
static class Vec{
double x;
double y;
public Vec(double x, double y) {
this.x = x;
this.y = y;
}
public double sum(){
return Math.sqrt(x * x + y * y);
}
}
static double ans;
static int N;
static Vec[] data;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
StringBuilder sb = new StringBuilder();
while( T-- >0){
ans =Double.MAX_VALUE;
N = Integer.parseInt(br.readLine());
data = new Vec[N];
double sumX=0, sumY=0;
for(int i =0;i<N;i++){
st = new StringTokenizer(br.readLine());
data[i] = new Vec(Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()));
sumX += data[i].x;
sumY += data[i].y;
}
solution(0, 0, new Vec(sumX, sumY));
sb.append(ans).append('\n');
}
System.out.println(sb);
}
public static void solution(int depth, int idx, Vec prev){
if(depth == N/2){
//N/2개를 이미 선택하여 뺏음
// for(int i =idx;i<N;i++){
// prev.x += data[i].x;
// prev.y += data[i].y;
// }
ans = Math.min(ans, prev.sum());
return;
}
for(int i= idx;i<N;i++){
//select하는 경우
solution(depth + 1, i+1, new Vec(prev.x -2*data[i].x, prev.y-2*data[i].y));
//합을 따로 구하지 않는다면 현재 값을 빼보고 구해본뒤
// 이후 더해서 다음 값을 확인한다.
// 대신 이 방법이면 10개를 고른 후 나머지에 대하여 다시 다 더해줘야한다.
// 이러한 문제 때문에 미리 다 더해놓고 빼주는 것이 더욱 빠르다.
//solution(depth + 1, i+1, new Vec(prev.x -data[i].x, prev.y-data[i].y));
// prev.x += data[i].x ;
// prev.y += data[i].y ;
//select하고 나서 다음거 보기전에 자신을 더해줌 및 원상복귀
}
}
}
'알고리즘 > 문제풀이' 카테고리의 다른 글
[백준] Q1766 문제집 JAVA (0) | 2022.02.19 |
---|---|
[백준] Q1202 보석도둑 JAVA (0) | 2022.02.19 |
[백준] Q13460 구슬탈출2 JAVA (0) | 2022.02.11 |
[백준] Q11049 행렬 곱셈 순서 (0) | 2022.02.11 |
[SWEA] 1855 영준이의 진짜 BFS JAVA (0) | 2022.02.09 |