[문제링크]

 

9934번: 완전 이진 트리

상근이는 슬로베니아의 도시 Donji Andrijevci를 여행하고 있다. 이 도시의 도로는 깊이가 K인 완전 이진 트리를 이루고 있다. 깊이가 K인 완전 이진 트리는 총 2K-1개의 노드로 이루어져 있다. (아래

www.acmicpc.net

 

0. 완전 이진 트리를 중위 순회한 결과가 주어졌을때, 원래의 트리를 복원하는 문제

 

1. 완전 이진 트리의 특성상, 왼쪽 subtree와 오른쪽 subtree의 크기가 동일하다

  • 중위 순회는 왼쪽 - 자신 - 오른쪽 순서로 이루어지므로, 정 가운데 번호가 항상 root노드이다

 

2. 시작-끝 값으로 subtree 정보를 유지하면서, 가운데(root) 정보를 저장하며 재귀를 진행한다

  • 재귀의 깊이에 따라 각 list에 저장
  • subtree의 크기가 0이되면 종료한다

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int N = pint(br.readLine());
		int[] node = new int[(int)Math.pow(2, N)-1];
		ArrayList<LinkedList<Integer>> list = new ArrayList<>();
		for(int i=0; i<N; i++) {
			list.add(new LinkedList<>());
		}
		StringTokenizer st = new StringTokenizer(br.readLine());
		for (int i = 0; i < node.length; i++) {
			node[i]=pint(st.nextToken());
		}
		
		rec(list, node, 0, node.length, 0);
		
		for(int i=0; i<N; i++) {
			for(Integer e : list.get(i)) {
				System.out.print(e+" ");
			}System.out.println();
		}
	}
	
	static void rec(ArrayList<LinkedList<Integer>> list, int[] node, 
			int fst, int lst, int depth) {
		
		if(fst==lst)return;
		int mid = (fst+lst)/2;
		
		list.get(depth).add(node[mid]);
		
		rec(list, node, fst, mid, depth+1);//left
		rec(list, node, mid+1, lst, depth+1);//right
	}
	
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

 

이 블로그 오는사람 70%는 파판9나 한글패치 관련 게시글이긴 한데.. 그래도 누군간 보겠지 싶어서 써봅니다

 

 

1. 취업 성공했습니다!

 

딱히 놀랍진 않게도 취준생 블로그였습니다 짜잔~

지원했던 회사 스펙트럼이 좀 넓은지라 하나하나 정리해서 간단하게 써보고싶긴한데, 아직 입사날짜만 기다리는 예비 직장인이라 좀 조심스럽네요.

언젠가 기회가 되면 작성해보겠습니다.

 

토익 성적도 2년 만료 직전이었고 졸업 후 지난 시간이 슬슬 년단위가 되가서 걱정스러웠는데, 연말에 좋은 소식 들을 수 있어서 다행이라고 생각합니다.

(몇달동안은 재택이라고 하니 싫어하시는 부모님...)

 

 

2. 게시글이 뜸했던 이유

 

연말 + 취업 성공 소식이 겹쳐서 친구들 만나서 놀고 한턱 내고 한것도 있지만, 그동안 못했던 취미쪽으로 시간 할애가 많아졌습니다.

최근에 한 걸로는

  • 섭종한 게임 데이터 파일 언패킹해서 이미지 추출하기
  • 암호화된 이미지 해제하려고 복호화 방법 / 암호화 기법들 들쑤시고 다니기
    • 실패했습니다.. 암호화 결과 + 128bit 암호화 키는 획득했는데 암호화 방법을 모르겠네요
  • 그랑블루 프로젝트 마저 진행
  • 좋아하는 게임 한글화를 위해 개발자와 소통중 (2021.12.26 기준 진행중)
  • + 물론 게임도 하는중

이런 짓을 하고 다니니 게시글로 정리할만한 내용이 쉽게 생기지 않네요...

 

 

3. 그랑블루 프로젝트는 배포 문제로 고민중입니다

 

프론트엔드 페이지도 거의 다 작성되었고, 배포해서 실제 테스트해봐도 괜찮겠다 싶은 단계가 되었습니다.

다만 이미지가 오고가는 작업이 있어서 트래픽이 좀 걱정되고, 프리티어도 끝나가는지라 AWS에는 무서워서 못올리고 라즈베리파이를 하나 사서 장난감 겸 간이 홈서버용으로 돌려볼 생각이었습니다.

라즈베리파이도 반도체 수급의 희생양이 되었다는걸 알기 전까지는 말이죠... 중고 아니고선 구할 방법이 없네요

 

일단 AWS에 배포하고, 트래픽 측정 기간을 좀 거친다음 결정할 생각입니다. 라즈베리 파이도 기왕 사는거 램 8G짜리는 사는게 좋을것같은데 다들 2/4G매물밖에 없네요.

 

 

지금까지 진행된 사항들 (영상참고)

 

  • ID와 메세지를 입력시 자동으로 Favorite 캐릭터와 소환수 정보를 크롤링, 이미지로 생성해준다
  • 데스크탑 / 모바일 각 4종씩 8종류의 배경 제공 (추가 가능)
  • 이미지 다운로드 가능 (웹 상 이미지는 크기 수정된 이미지, 다운로드는 원본)
  • 이미지 + 정보 텍스트를 전용 트위터 계정에 공유 가능

 

 

앞으로 진행할? 사항들

 

  • 일정 시간 내 동일 ID 중복실행 방지
    • 변경사항 반영하지 않고 기존 생성된 이미지 반환할 예정
    • Twitter 업로드도 불가능
    • 일정 시간마다 작업한 이미지들 삭제하는것도 가능..한가?
  • 프론트엔드 페이지 좀 꾸미기
    • 하지만 결과는 처참했다!
  • 검색기능 구현
    • 1. 요구사항에 맞게 트위터 업로드 결과 필터링해서 보여주기 (최선)
    • 2. 요구사항에 맞는 트위터 검색 결과 페이지로 redirect (차선)
    • 3. 트위터에 검색할 수 있는 문자열 제공 (최소)
  • error 페이지 구현 및 세부 에러/예외처리
  • chrome의 업데이트에 따른 chromedriver문제 해결 고민하기..

 

사유 : static 폴더에 생성된 이미지는 서버 구동 이후에 자동으로 업데이트되지 않음

Spring devtools를 쓰면 된다고 하지만, intellij에서 추가적인 설정도 필요하고,

init 단계가 반복 호출되면 망가져서 사용 불가

결국 File을 백엔드에서 프론트로 직접 전달(byte[]의 형태로)

 

 

1. File을 byte[]로 변경해 전송하기 (백엔드)

 

@GetMapping("/getImage/{id}")
public ModelAndView getImage(@PathVariable String id,
                                    ModelAndView mav){
    try (InputStream inputStream = new FileInputStream("src/main/resources/static/image/"+id+".jpg")){
        byte[] byteArray = IOUtils.toByteArray(inputStream); // to byte array
        mav.addObject("playerImg",Base64.getEncoder().encodeToString(byteArray)); // base64 encode
        mav.setViewName("playerInfo"); // set html file
        return mav;
    }catch (Exception e){
        mav.setViewName("redirect:/error");
        return mav;
	}
}
  • File을 받아온 후, byte[]로 변경해서 사용, common-io의 IOUtils를 사용하였다 (링크)
  • 원활한 사용을 위해 base64로 인코딩하였다
  • try-with-resources를 이용, close문은 생략 가능

 

 

2. 전송받은 byte[] 표시 및 다운로드 제공 (프론트)

 

<img th:src="'data:image/jpeg;base64,'+${playerImg}">
<a download="Profile.jpg" th:href="'data:image/jpeg;base64,'+${playerImg}">다운로드!</a>
  • download 속성 값을 변경해 다운로드 파일 이름 변경 가능
  • JSP나 기타 방식으로도 문법만 일치시키면 동일하게 사용 가능하다

 

 

3. 적용 결과

 

결과 화면

  • 좌측 웹 사이트에서 이미지 정상 출력
  • 우측 다운로드 이미지 정상 출력

[이전글]

 

 

대충 취업준비 스터디 이런저런사정 등등으로 바빠서 한동안 작업하기도 힘들었고... 글로 정리하기도 힘들었습니다

 

일단 현재 시점까지 작업한 내용으론

 

 

1. Spring boot기반으로 변경

  • 외부 lib 매번 파일로 넣고 설정해주기 귀찮다...
  • Maven/Gradle 최고!
  • properties 관리도 최고!!
  • @Autowired랑 자동 싱글톤도 최고!!!

 

 

2. 이미지 생성 수정

<<이전                     현재>>

  • 이름, 랭크 등 출력 (ID 추가 예정)
  • 소환석 정보 속성에 맞춰 배치 및 레벨/이름 출력
  • 최대 3줄까지 메세지 입력받아 이미지에 출력
  • 계정의 favorite 캐릭터를 받아와서 배경에 함께 출력 (기본 : 루리아)

 

 

3. 트위터 업로드 기능 구현

  • ID / 이름 / 소환석 정보를 포함
  • 생성된 이미지 포함 자동 업로드
  • Twitter4j는 Java 11에서 잘 작동하지 않나..? 8로 내리니까 많은 문제가 해결됬다

[문제링크]

 

2668번: 숫자고르기

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절

www.acmicpc.net

 

0. Cycle을 탐색하는 DFS문제

 

1. 여러 칸들을 선택했을때, index와 내용이 같으려면 해당 칸들 사이에 cycle이 발생해야한다

  • ex. (1,3), (3,5), (5,1)이 있다면, 1->3->5->1로 cycle이 발생하게 된다
  • ex2. (2,1), (1,3), (3,5), (5,1)의 경우, 2->1->3->5->1로 2가 누락되니 cycle이 아니다

 

2. 각 칸별로 DFS를 돌며 자기 자신으로 돌아올 수 있는지, 즉 cycle 발생 여부를 탐색한다

  • 발생까지 거친 node들은 전부 Queue에 저장한다

 

3. Cycle이 발생했다면, 해당 node들은 cycle에 속한다는 의미로 방문 처리해 DFS 재탐색을 막는다

  • 또한 오름차순으로 정렬되도록 PriorityQueue를 사용해 저장한다

 

4. 모든 node에 대한 DFS 탐색이 종료되었다면, PQ의 size와 그 원소를 차례대로 출력한다

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;

public class Main{
	static int[] num;
	static boolean[] isVisit;
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		//dfs, 사이클 생성 탐색
		
		int N = pint(br.readLine());
		num = new int[N+1];
		boolean[] isPartOfCycle = new boolean[N+1];
		
		for (int i = 1; i <= N; i++) {
			num[i]=pint(br.readLine());
		}
		
		PriorityQueue<Integer> pq = new PriorityQueue<>();
		Queue<Integer>qu = new LinkedList<>();
	
		for(int i=1; i<=N; i++) {
			if(isPartOfCycle[i])continue;
			
			isVisit = new boolean[N+1];
			//do search
			if(dfs(i,i, qu)) {
				for(Integer element : qu) {
					pq.offer(element);
					isPartOfCycle[element]=true;
				}
			}
			qu.clear();
		}
		
		System.out.println(pq.size());
		while(!pq.isEmpty())System.out.println(pq.poll());
	}
	
	static boolean dfs(int fst, int cur, Queue<Integer>qu) {
		
		if(cur==fst && isVisit[cur])return true;
		if(isVisit[cur])return false;
		qu.offer(cur);
		isVisit[cur]=true;
		return dfs(fst, num[cur], qu);
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

4485번: 녹색 옷 입은 애가 젤다지?

젤다의 전설 게임에서 화폐의 단위는 루피(rupee)다. 그런데 간혹 '도둑루피'라 불리는 검정색 루피도 존재하는데, 이걸 획득하면 오히려 소지한 루피가 감소하게 된다! 젤다의 전설 시리즈의 주

www.acmicpc.net

 

0. 가능한 적은 누적 숫자로 목표 지점에 도달하는 문제. BFS

 

1. 기본적인 큐를 이용한 BFS를 진행한다

 

2. cache 배열을 관리해, 어떠한 지점에 도달한 숫자의 최솟값을 저장한다

  • 더 큰 숫자로 해당 지점에 도달한 경우, 더 이상 진행할 가치가 없다는 뜻. 소거한다
  • cache 배열 초깃값은 문제 조건상 최댓값이 125*125*9 = 대략 14만이니, 그보다 큰 수 아무거나 입력한다

 

3. 어떤 지점에 같은 시점에 도달했을 경우, cache 배열이 여러번 갱신되며 큐에 같은 지점이 중복 삽입된다

  • isCached boolean 배열을 관리해, 중복 삽입을 막는다
  • Queue 기능을 하면서 Set인게 있나..? 있으면 좋을것같다

 

4. 모든 탐색이 끝난 후, 목표 지점인 [N][N] (배열 인덱스로는 [N-1][N-1]) 지점의 cache 값이 정답

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main{
	static int[][] dir = {
		{1,0},{0,1},{-1,0},{0,-1}
	};
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		
		int probCnt=1;
		while(true) {
			int N = pint(br.readLine());
			if(N==0)break;
            
			int[][]map = new int[N][N];
			int[][]cache = new int[N][N];
			boolean[][]isCached = new boolean[N][N];
			
			for (int i = 0; i < N; i++) {
				Arrays.fill(cache[i], 100000000);
				StringTokenizer st = new StringTokenizer(br.readLine());
				for (int j = 0; j < N; j++) {
					map[i][j]=pint(st.nextToken());
				}
			}
			
			Queue<int[]> qu = new LinkedList<int[]>();
			qu.offer(new int[] {0,0});
			isCached[0][0]=true;
			cache[0][0]=map[0][0];
			
			while(!qu.isEmpty()) {
				int[] cur = qu.poll();
				isCached[cur[0]][cur[1]]=false;
				
				for(int d=0; d<4; d++) {
					int nx = cur[0]+dir[d][0];
					int ny = cur[1]+dir[d][1];
					
					if(nx<0||nx>=N||ny<0||ny>=N)continue;
					
					if(cache[nx][ny] > map[nx][ny]+cache[cur[0]][cur[1]]) {
						cache[nx][ny] = map[nx][ny]+cache[cur[0]][cur[1]];
						if(!isCached[nx][ny]) {
							isCached[nx][ny]=true;
							qu.offer(new int[] {nx,ny});
						}
					}
				}
			}
			sb.append("Problem ").append(probCnt++).append(": ").append(cache[N-1][N-1]).append("\n");
			
		}
		System.out.println(sb);
		
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

'알고리즘 문제 풀이 > BOJ 골드' 카테고리의 다른 글

[백준] 15684 - 사다리 조작  (0) 2022.02.17
[백준] 2293 - 동전 1  (0) 2022.01.31
[백준] 2668 - 숫자 고르기  (0) 2021.11.27
[백준] 11758 - CCW  (0) 2021.11.15
[백준] 2470 - 두 용액  (0) 2021.11.15
[백준] 2631 - 줄세우기  (0) 2021.11.15
[백준] 1959 - 달팽이3  (0) 2021.11.04

https://twitter.com/painter_of_100

 

재미있는 프로그래머 개그가 있어요

프사 N차가공 무단전재 가능(비영리)

+ Recent posts