Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9주차] 백제완 #124

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions BOJ/1000-5000번/JW_2660.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class JW_2660 {

static final int INF = Integer.MAX_VALUE >> 2;

public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
// 그래프 선언 및 초기화
int[][] graph = new int[n + 1][n + 1];
for (int i = 0; i < n + 1; i++) {
Arrays.fill(graph[i], INF);
graph[i][i] = 0;
}
while (true) {
StringTokenizer st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
// 종료 조건
if (u == -1 && v == -1)
break;
// 양방향 그래프
graph[u][v] = 1;
graph[v][u] = 1;
}
// 플로이드 와샬
for (int k = 1; k < n + 1; k++)
for (int i = 1; i < n + 1; i++)
for (int j = 1; j < n + 1; j++)
if (graph[i][j] > graph[i][k] + graph[k][j]) {
graph[i][j] = graph[i][k] + graph[k][j];
}
int min = 50; // 최소 스코어
ArrayList<Integer> al = new ArrayList<>();
for (int i = 1; i < n + 1; i++) {
int score = 0;
// 최단 거리 중 최댓값 찾기
for (int j = 1; j < n + 1; j++)
score = Math.max(score, graph[i][j]);
// 최솟값을 갱신 할 수 있다면
if (min > score) {
min = score; // 최솟값 갱신
al.clear(); // 리스트 비우기
al.add(i); // 리스트에 추가
// 최솟값과 동일하면
} else if (min == score)
al.add(i); // 리스트에 추가
}
StringBuilder sb = new StringBuilder();
sb.append(max).append(" ").append(al.size()).append("\n");
for (int i : al) {
sb.append(i).append(" ");
}
System.out.println(sb);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제완님! 플로이드로 푸셨길래 문제에서 이해 안되는 부분 질문 드립니다
문제에서 구하는게 회장의 점수와 회장이 될 수 있는 모든 사람이잖아요
그래서 모든 회원 간의 점수를 구해서 점수가 가장 적은 사람(회장)을 구해야하는데 예시가.. 이해 안됩니다ㅠㅠ

"예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다."

점수 1점 : 회원A-회원B 친구
점수 2점 : 다른 모든 회원이 친구(1점) or 친구의 친구
점수 3점 : 다른 모든 회원이 친구(1점) or 친구의 친구(2점) or 친구의 친구의 친구

"각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다. " -> 최단 거리를 고려(??)

모든 사람 최소 점수 구하기 -> 플로이드???
예시가 이해가 잘안되어서 그런지 왜 최단 거리를 구해야되는지 잘모르겠습니다ㅠ_ㅠ

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혜원님! 점수를 누적하는게 아니라 한 회원의 모든 친구 정보를 파악해서 최종 점수를 매기는 것 입니다!

  • 점수 1점: 한 회원(A)가 모든 회원과 친구로 연결됨(거리: 1)
  • 점수 2점: 한 회원(A)가 B와 친구의 친구로 연결되고(거리: 2), 나머지 회원과는 친구로 연결됨(거리: 1)

이런식으로 점수를 계산하기 때문에 한 회원이 다른 회원으로 가는 최단거리를 구해서 그 값중 가장 먼 값이 점수가 됩니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일단 문제에서 플로이드 와샬을 적용하는 이유를 알려드릴게요!

  1. 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다.
  2. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다.
  3. 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점

일단 1번 조건으로 인해서 모든 회원들은 이어질 수 있다는 점을 파악해야 합니다.
2번 조건에 의해 각 회원은 다른 회원들과 가까운 정도(회원과 회원의 최단 거리)에 따라서 점수를 얻기 때문에 회원 간의 최단 거리를 구해야 합니다.
3번 조건에 의해서는 직접 알고 있는 회원들은 1의 거리를 갖는다는 키워드를 파악하면 됩니다.
따라서 직접 연결되지 않고 타인을 통해서 알게 되는 사람과의 거리는 둘을 연결해주는 사람의 수 +1 점수를 갖게 됩니다.

예를 들어 1 → 2의 점수를 정할 때, 1과 2가 직접 연결되지 않았으면 다른 사람을 통해서 점수를 계산해야 합니다.
1 → 3 → 2 와 같은 경우는 2의 점수를 갖고
1 → 4 → 5 → 2 와 같은 경우는 3의 점수를 갖습니다.
하지만 문제에서는 가까운 정도를 원하기에 최솟값인 2의 점수가 1 → 2의 점수가 됩니다.
따라서 이 문제에서는 모든 회원과 다른 모든 회원들과의 최단 거리를 구해줘야 하므로 플로이드 와샬이 적합한 알고리즘이었습니다!

예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다.
어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다.
또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.

해당 조건에 의해서 한 회원의 최단 거리 정보들 중에서 최댓값이 해당 회원의 최종 점수가 됩니다.

여기서 이해 안 가시는 부분 추가적으로 작성해주시면 도움드릴게요!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두 분 모두 방향 잡아주셔서 정말 감사합니다 ㅠㅠ

제가 예시를 잘못 이해하고 있었네요

다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.

예시를 잘못 이해해서.. 어떤 경우에 2점인지 3점인지.. 이해를 못하고 있었습니다
가까운 정도 -> 거리로 생각 해야되는 문제였군요...!

점수 : 특정 회원이 다른 모든 회원과 연결되위해 가까운 정도 ->최솟값
회장 : 점수가 가장 낮은 사람(가장 가까운 거리에 있는 사람) -> 최단거리
조건 : 몇 사람을 통하면 모두가 서로알 수 있다 = 모든 회원(노드)가 연결되어 있음
=> 모든 회원과 다른 모든 회원들과의 최단 거리 구하기 -> 플로이드

질문 드리고 또 잘못된 방향으로 이해하고 있었습니다..

1->3->2 2점, 1->4->5->2 3점, 그럼 1->2 관계는 3점 인가?? 이러고 있었습니다ㅎ.. 점수가 최솟값이었군요

제가 올바르게 이해한게 맞을까요.....?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

거리는 최딘 거리로 하지만 그 해당 회원의 점수는 최단 거리들 중 최댓값으로
입니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
WITH CTE AS (
SELECT
*
FROM
CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE
START_DATE <= '2022-11-30'
AND END_DATE >= '2022-11-01'
)

SELECT
A.CAR_ID
, A.CAR_TYPE
, FLOOR(30 * (A.DAILY_FEE * (1 - C.DISCOUNT_RATE / 100))) FEE
FROM
CAR_RENTAL_COMPANY_CAR A
LEFT JOIN CTE B
ON A.CAR_ID = B.CAR_ID
INNER JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN C
ON A.CAR_TYPE = C.CAR_TYPE
WHERE
A.CAR_TYPE IN ('SUV', '세단')
AND B.CAR_ID IS NULL
AND C.DURATION_TYPE LIKE '30%'
AND FLOOR(30 * (A.DAILY_FEE * (1 - C.DISCOUNT_RATE / 100))) BETWEEN 500000 AND 2000000
ORDER BY
FEE DESC
, A.CAR_TYPE
, A.CAR_ID