Skip to content

Commit f737c69

Browse files
authored
Merge branch 'main' into lkhyun
2 parents d14508a + 127b12e commit f737c69

File tree

256 files changed

+20115
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

256 files changed

+20115
-5
lines changed

.github/auto_assign.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Set to true to add reviewers to pull requests
2+
addReviewers: false
3+
4+
# Set to true to add assignees to pull requests
5+
addAssignees: author
6+
7+
# A list of keywords to be skipped the process that add reviewers if pull requests include it
8+
skipKeywords:
9+
- wip
10+
11+
# A number of reviewers added to the pull request
12+
# Set 0 to add all the reviewers (default: 0)
13+
numberOfReviewers: 0

.github/workflows/CI.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: 자동 통합 CI
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, synchronize]
6+
7+
jobs:
8+
merge:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout code
13+
uses: actions/checkout@v2
14+
15+
- name: Set up Node.js
16+
uses: actions/setup-node@v2
17+
with:
18+
node-version: '14'
19+
20+
- name: Install dependencies
21+
run: npm install
22+
23+
- name: Merge pull requests
24+
run: |
25+
TODAY=$(TZ='Asia/Seoul' date +%Y%m%d)
26+
27+
PRS=$(gh pr list --state open --base main --json number,title --jq '.[] | select(.title | startswith("[" + "'"$TODAY"'" + "]")) | .number')
28+
for pr in $PRS; do
29+
echo "Merging PR #$pr"
30+
gh pr merge $pr --merge --admin
31+
done
32+
env:
33+
GITHUB_TOKEN: ${{ secrets.TOKEN }}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
```java
2+
import java.util.*;
3+
import java.io.*;
4+
5+
public class Main {
6+
7+
public static void main(String[] args) throws IOException {
8+
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
9+
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
10+
11+
int T = Integer.parseInt(br.readLine());
12+
for (int tc = 1; tc <= T; tc++) {
13+
int n = Integer.parseInt(br.readLine());
14+
15+
// TreeMap: 자동정렬(오름차순)을 보장하며, 키 기반 탐색 성능 logN
16+
Map<Integer, List<Integer>> map = new TreeMap<>();
17+
map.put(-1, new ArrayList<>(Arrays.asList(0)));
18+
StringTokenizer st;
19+
for (int i = 0; i < n; i++) {
20+
st = new StringTokenizer(br.readLine());
21+
int x = Integer.parseInt(st.nextToken());
22+
int y = Integer.parseInt(st.nextToken());
23+
24+
if (map.containsKey(x)) {
25+
map.get(x).add(y);
26+
} else {
27+
List<Integer> val = new ArrayList<>();
28+
val.add(y);
29+
map.put(x, val);
30+
}
31+
}
32+
33+
int[] keys = map.keySet().stream().mapToInt(x -> x).toArray();
34+
for (int i = 0; i < keys.length; i++) {
35+
int key = keys[i];
36+
37+
if (key == -1) continue;
38+
39+
if (map.get(key).size() == 1) {
40+
continue;
41+
}
42+
43+
// 이전 x좌표의 마지막 y좌표와 비교해서
44+
// 같은 x좌표를 가진 좌표들 중 가장 먼저 도달하는 y좌표를 구한다.
45+
int prevKey = keys[i-1];
46+
int lastIndex = map.get(prevKey).size() - 1;
47+
int firstY = map.get(prevKey).get(lastIndex);
48+
49+
// 현재 x좌표의 y좌표들 중 가장 값이 큰 y좌표를 찾는다
50+
int maxY = Collections.max(map.get(key));
51+
52+
// firstY가 maxY라면 내림차순 정렬
53+
// firstY가 maxY가 아니라면 오름차순 정렬
54+
if (firstY == maxY) {
55+
Collections.sort(map.get(key), Collections.reverseOrder());
56+
}
57+
else {
58+
Collections.sort(map.get(key));
59+
}
60+
}
61+
List<String> points = new ArrayList<>(n);
62+
for (int x : keys) {
63+
List<Integer> values = map.get(x);
64+
for (int y : values) {
65+
points.add(x + " " + y);
66+
}
67+
}
68+
69+
int[] tmp = Arrays.stream(br.readLine().split(" "))
70+
.mapToInt(x -> Integer.parseInt(x))
71+
.toArray();
72+
int total = tmp[0];
73+
for (int i = 1; i <= total; i++) {
74+
bw.write(points.get(tmp[i]) + "\n");
75+
}
76+
}
77+
78+
br.close();
79+
bw.flush();
80+
bw.close();
81+
}
82+
}
83+
```
84+
- `TreeMap` 사용
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
```java
2+
import java.io.*;
3+
import java.util.*;
4+
5+
public class Main {
6+
7+
private static class Node implements Comparable<Node>{
8+
int r;
9+
int c;
10+
int weight;
11+
public Node(int r, int c, int weight) {
12+
this.r = r;
13+
this.c = c;
14+
this.weight = weight;
15+
}
16+
17+
public String toString() {
18+
return "(" + r + ", " + c + ", time:" + weight + ")";
19+
}
20+
21+
@Override
22+
public int compareTo(Node o) {
23+
return Integer.compare(this.weight, o.weight);
24+
}
25+
}
26+
27+
private static int N;
28+
private static int M;
29+
private static int T;
30+
private static int D;
31+
private static int[][] arr;
32+
private static int[] dr = {0, 0, -1, 1};
33+
private static int[] dc = {-1, 1, 0, 0};
34+
private static final int INF = Integer.MAX_VALUE;
35+
private static List<List<Node>> graph;
36+
37+
public static void main(String[] args) throws IOException {
38+
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
39+
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
40+
41+
StringTokenizer st = new StringTokenizer(br.readLine());
42+
N = Integer.parseInt(st.nextToken());
43+
M = Integer.parseInt(st.nextToken());
44+
T = Integer.parseInt(st.nextToken());
45+
D = Integer.parseInt(st.nextToken());
46+
47+
arr = new int[N][M];
48+
for (int i = 0; i < N; i++) {
49+
char[] tmpChar = br.readLine().toCharArray();
50+
for (int j = 0; j < M; j++) {
51+
if (Character.isLowerCase(tmpChar[j])) {
52+
arr[i][j] = tmpChar[j] - 'a' + 26;
53+
} else {
54+
arr[i][j] = tmpChar[j] - 'A';
55+
}
56+
}
57+
}
58+
59+
// 인접리스트 생성
60+
graph = new ArrayList<>();
61+
for (int i = 0; i < N * M; i++) {
62+
graph.add(new ArrayList<>());
63+
}
64+
for (int r = 0; r < N; r++) {
65+
for (int c = 0; c < M; c++) {
66+
67+
int index = r * M + c;
68+
69+
for (int i = 0; i < 4; i++) {
70+
int nr = r + dr[i];
71+
int nc = c + dc[i];
72+
if (nr < 0 || nr >= N || nc < 0 || nc >= M) {
73+
continue;
74+
}
75+
76+
// 높이의 차이가 T보다 크지 않은 곳으로만 다닐 수 있다.
77+
if (Math.abs(arr[nr][nc] - arr[r][c]) > T) {
78+
continue;
79+
}
80+
81+
int time;
82+
if (arr[r][c] >= arr[nr][nc]) {
83+
time = 1;
84+
} else {
85+
time = (int)Math.pow(arr[nr][nc] - arr[r][c], 2);
86+
}
87+
88+
graph.get(index).add(new Node(nr, nc, time));
89+
}
90+
91+
}
92+
}
93+
94+
// 시작점 0에서 각 점까지의 최단거리
95+
int[] dist = dijkstra(new Node(0, 0, 0));
96+
97+
// 시작점에서 최단경로가 존재하는 정점 중, 제한 시간 내에 다시 시작점으로 돌아올 수 있는 경우
98+
int highest = arr[0][0];
99+
for (int mountain = 1; mountain < N*M; mountain++) {
100+
if (dist[mountain] != INF) {
101+
int mountC = mountain % M;
102+
int mountR = mountain / M;
103+
104+
if (highest >= arr[mountR][mountC]) continue;
105+
106+
int[] backDist = dijkstra(new Node(mountR, mountC, 0));
107+
if (dist[mountain] + backDist[0] <= D) {
108+
highest = arr[mountR][mountC];
109+
}
110+
}
111+
}
112+
113+
bw.write(highest + "\n");
114+
115+
br.close();
116+
bw.flush();
117+
bw.close();
118+
}
119+
120+
private static int[] dijkstra(Node start) {
121+
int[] dist = new int[N * M];
122+
Arrays.fill(dist, INF);
123+
124+
int startIdx = start.r * M + start.c;
125+
dist[startIdx]= 0;
126+
127+
PriorityQueue<Node> pq = new PriorityQueue<>();
128+
pq.offer(start);
129+
130+
while (!pq.isEmpty()) {
131+
Node node = pq.poll();
132+
int nodeIdx = node.r * M + node.c;
133+
134+
List<Node> nextNodes = graph.get(nodeIdx);
135+
for (Node nextNode : nextNodes) {
136+
int nextIdx = nextNode.r * M + nextNode.c;
137+
int nextDist = dist[nodeIdx] + nextNode.weight;
138+
if (nextDist < dist[nextIdx]) {
139+
dist[nextIdx] = nextDist;
140+
pq.offer(new Node(nextNode.r, nextNode.c, nextDist));
141+
}
142+
}
143+
}
144+
145+
return dist;
146+
}
147+
}
148+
```
149+
- 주어진 입력을 인접 리스트 형태의 그래프로 변환
150+
- 시작점에서 dijkstra로 최단경로를 구한 뒤, 각 정점에서 시작점으로 제한시간 내에 돌아올 수 있는지 한번 더 체크
151+
- 유의사항
152+
- 시작점의 높이가 가장 높은 경우도 있을 수 있음
153+
- `highest`를 0으로 초기화하는 것이 아니라 시작점의 높이로 초기화
154+
- 테스트케이스
155+
```
156+
3 3 51 1000
157+
zAA
158+
AAA
159+
AAA
160+
```
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
```java
2+
import java.util.*;
3+
import java.io.*;
4+
5+
public class Main {
6+
public static void main(String[] args) throws IOException {
7+
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
8+
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
9+
10+
int N = 20;
11+
int[][] arr = new int[N][N];
12+
13+
// 검사 방향: 아래, 우상향, 좌하향, 우측
14+
int[] dr = {1, -1, 1, 0};
15+
int[] dc = {0, 1, 1, 1};
16+
17+
for (int i = 1; i < N; i++) {
18+
StringTokenizer st = new StringTokenizer(br.readLine());
19+
for (int j = 1; j < N; j++) {
20+
arr[i][j] = Integer.parseInt(st.nextToken());
21+
}
22+
}
23+
24+
int winner = 0;
25+
int winnerR = 0;
26+
int winnerC = 0;
27+
28+
for (int r = 1; r < N; r++) {
29+
for (int c = 1; c < N; c++) {
30+
31+
if (winner > 0) break; // 승부 결정 완료
32+
if (arr[r][c] == 0) continue;
33+
34+
// 방향 체크
35+
for (int i = 0; i < 4; i++) {
36+
37+
int cnt = 1; // (r, c)에서 시작, 연속된 바둑돌 개수 카운트
38+
int nr = r + dr[i];
39+
int nc = c + dc[i];
40+
41+
while (1 <= nr && nr < N && 1 <= nc && nc < N) {
42+
if (arr[nr][nc] != arr[r][c]) {
43+
break;
44+
}
45+
nr += dr[i];
46+
nc += dc[i];
47+
cnt++;
48+
}
49+
50+
// i방향으로 연속된 바둑돌이 5개인 경우
51+
if (cnt == 5) {
52+
// (r, c) 이전의 바둑돌 색상을 확인하여 6개 이상인지 체크
53+
int prevR = r - dr[i];
54+
int prevC = c - dc[i];
55+
56+
boolean isValid = false;
57+
if (1 <= prevR && prevR < N && 1 <= prevC && prevC < N) {
58+
if (arr[r][c] != arr[prevR][prevC]) {
59+
isValid = true;
60+
}
61+
}
62+
else { // 이전의 바둑돌이 없다면 5개임이 보장
63+
isValid = true;
64+
}
65+
66+
if (isValid) {
67+
winner = arr[r][c];
68+
winnerR = r;
69+
winnerC = c;
70+
break; // 승부 결정 완료
71+
}
72+
}
73+
}
74+
}
75+
}
76+
77+
bw.write(winner + "\n");
78+
if (winner > 0) {
79+
bw.write(winnerR + " " + winnerC);
80+
}
81+
82+
83+
br.close();
84+
bw.flush();
85+
bw.close();
86+
}
87+
}
88+
89+
```
90+
91+
- (r, c)에서 ⬇↗↘➡ 방향으로 진행해서 같은 색 바둑돌 5개를 찾은 경우
92+
93+
- 육목일 가능성이 없는지 진행 방향의 반대 방향으로 가서 확인
94+
95+
- `틀렸습니다` 받은 이유
96+
- 육목 가능성 체크하기 위해 반대 방향의 좌표 (prevR, prevC)룰 구할 때
97+
- (prevR, prevC)가 범위를 벗어난다면 해당 케이스는 오목임이 보장됨
98+
- 범위 벗어나는 경우 생각 못하고 `범위 내에 있을때, (r, c)와 같은 색 바둑돌인지`만 체크했던 실수💥
99+
100+
- 가능한 케이스들을 꼼꼼히 생각해 보는 것이 중요

0 commit comments

Comments
 (0)