[프로그래머스] 야근 지수 (java) Dynamic_programming

2020-03-24

야근 지수 (프로그래머스> Dynamic_programming)

문제 링크

문제설명

회사원 Demi는 가끔은 야근을 하는데요, 야근을 하면 야근 피로도가 쌓입니다. 야근 피로도는 야근을 시작한 시점에서 남은 일의 작업량을 제곱하여 더한 값입니다. Demi는 N시간 동안 야근 피로도를 최소화하도록 일할 겁니다.Demi가 1시간 동안 작업량 1만큼을 처리할 수 있다고 할 때, 퇴근까지 남은 N 시간과 각 일에 대한 작업량 works에 대해 야근 피로도를 최소화한 값을 리턴하는 함수 solution을 완성해주세요.

제한 사항
  • works는 길이 1 이상, 20,000 이하인 배열입니다.
  • works의 원소는 50000 이하인 자연수입니다.
  • n은 1,000,000 이하인 자연수입니다.
입출력 예
works n result
[4, 3, 3] 4 12
[2, 1, 2] 1 6
[1,1] 3 0
입출력 예 설명

입출력 예 #1 n=4 일 때, 남은 일의 작업량이 [4, 3, 3] 이라면 야근 지수를 최소화하기 위해 4시간동안 일을 한 결과는 [2, 2, 2]입니다. 이 때 야근 지수는 22 + 22 + 22 = 12 입니다.

입출력 예 #2 n=1일 때, 남은 일의 작업량이 [2,1,2]라면 야근 지수를 최소화하기 위해 1시간동안 일을 한 결과는 [1,1,2]입니다. 야근지수는 12 + 12 + 22 = 6입니다.

입출력 예 #3


풀이

package Dynamic_programming;

import java.util.*;

public class prog_3_야근지수 {

	//1h
    static public long solution(int n, int[] works) {
        long answer = 0;
        PriorityQueue<Integer> qu = new PriorityQueue<>(); // min heap
        //PriorityQueue<Integer> max_heap = new PriorityQueue<>(Collections.reverseOrder()); ->max heap 만드는 법
        
        
        int len = 0;
        for(int i=0;i<works.length; i++) {
        	len += works[i];
        	qu.add(-1 * works[i]); //min힙이니까 -1 곱해줘서 풀어주고
        }
        
        
        if(len <= n)
        	return 0;
        
        else {
        	while(n>0) {
        		int max = qu.poll();
        		System.out.println(max);
        		qu.add(max+1); //-를 곱해놨으니까 +1해줘야 빼지는 개념
        		n--;
        	}
        }
        
        int size = qu.size();
        for(int i=0;i<size; i++) {
        	answer += Math.pow(-1 * qu.poll(), 2); // -1해줬던걸 다시 +로 바꿔준뒤 제곱해준다
        }
        
        return answer;
    }
    
    public static void main(String[] args) {
		int w[] = {4,3,3};
		
		System.out.println(solution(4,w));
	}
}

후기 (1h)

하루가 지날 때마다 제일 큰값을 하나씩 빼준다는 개념을 빠르게 파악할 수 있다면, n–될 때마다 최대값을 찾아 빼주면 됐다.

  1. 하지만 일반 리스트에 sort함수를 매번 사용하면 시간초과가 뜨기 때문에
  2. 검색에 속도가 빠른 PriorityQueue를 사용했다
  3. PriorityQueue는 default가 minheap으로 되어있기때문에, poll()할때마다 제일 작은 값이 빠져서 이를 해결하기위해 모든 값에 -1을 곱해주었다
  4. -1을 곱해준 값들에는 +1을 해주어 빼는 연산을 해주었고
  5. 나중에 나온 값의 제곱을 더해 문제를 해결했다


정말 하나씩 빼줘야 한다는 생각은 했는데, 너무 수학적인 문제들이 많다…

그리고 검색이 오래걸릴때는 pq를 사용해준다는 것, 초기화할 때 reverseOrder()를 사용하면 maxheap으로 사용할 수 있다.

Read More

[프로그래머스] 여행경로 (java) Dfs

2020-03-24

여행경로 (프로그래머스> Dfs_Bfs)

문제 링크

문제설명

주어진 항공권을 모두 이용하여 여행경로를 짜려고 합니다. 항상 ICN 공항에서 출발합니다.

항공권 정보가 담긴 2차원 배열 tickets가 매개변수로 주어질 때, 방문하는 공항 경로를 배열에 담아 return 하도록 solution 함수를 작성해주세요.

제한사항
  • 모든 공항은 알파벳 대문자 3글자로 이루어집니다.
  • 주어진 공항 수는 3개 이상 10,000개 이하입니다.
  • tickets의 각 행 [a, b]는 a 공항에서 b 공항으로 가는 항공권이 있다는 의미입니다.
  • 주어진 항공권은 모두 사용해야 합니다.
  • 만일 가능한 경로가 2개 이상일 경우 알파벳 순서가 앞서는 경로를 return 합니다.
  • 모든 도시를 방문할 수 없는 경우는 주어지지 않습니다.
입출력 예
tickets return
[[ICN, JFK], [HND, IAD], [JFK, HND]] [ICN, JFK, HND, IAD]
[[ICN, SFO], [ICN, ATL], [SFO, ATL], [ATL, ICN], [ATL,SFO]] [ICN, ATL, ICN, SFO, ATL, SFO]
입출력 예 설명

예제 #1

[ICN, JFK, HND, IAD] 순으로 방문할 수 있습니다.

예제 #2

[ICN, SFO, ATL, ICN, ATL, SFO] 순으로 방문할 수도 있지만 [ICN, ATL, ICN, SFO, ATL, SFO] 가 알파벳 순으로 앞섭니다.


풀이

package Dfs_Bfs;

import java.util.*;


//2h
public class prog_3_여행경로 {
	static ArrayList<String> list = new ArrayList<>();
	
	static void dfs(String tic[][], String start, String s, boolean visited[], int size) {
		s = s + start + ","; //들어온거 넣어주고
		
		if(size == tic.length) {
			list.add(s);
			return ;
		}
			
		for(int i=0; i<tic.length; i++) {
			if(tic[i][0].equals(start) && !visited[i]) {
				visited[i] = true;
				dfs(tic,tic[i][1], s, visited, size+1);
				visited[i] = false; //!!! visited 하나만 사용하기때문에 나오면서 false 해줘야한다
			}
		}
		
	}
	
    static public String[] solution(String[][] tickets) {
       
    	for(int i=0;i<tickets.length; i++) {
    		boolean visited[] = new boolean[tickets.length];
    				
    		if(tickets[i][0].equals("ICN")) {
    			visited[i] = true;
    			dfs(tickets, tickets[i][1], "ICN,",visited,1);
    			visited[i] = false; //!!!visited 하나만 사용하기때문에 나오면서 false 해줘야한다
    		}
    	}
    
    	
    	list.sort(null);
    	String real[] = list.get(0).split(",");
    	String answer[] = new String[real.length];
    	
    	for(int i=0;i<answer.length; i++)
    		answer[i] = real[i];
    	
        return answer;
    }
	
	public static void main(String[] args) {
		String s[][] = {"ICN","COO"},{"ICN","BOO"}, {"COO","ICN"}, {"BOO","DOO"}};
		
		String ss[] = solution(s);
		
		for(int i=0; i<ss.length; i++)
			System.out.println(ss[i]);
		
	}
}

후기 (2h)

처음에는 이차원 배열을 1번째로 오름차순 정렬하려고 했는데, 그렇게되면 ICN으로 시작하는 많은 것들에는 대응할 수가 없었다.
따라서 방법을 바꿔서 티켓배열을 통째로 dfs돌면서 방문했는지 안했는지는 visit 배열을 사용해주었다.

  • 여기서 키포인트는!!!!
  • DFS 메소드를 만들 때, String 을 통째로 가져 가면서 방문하는 곳을 모두 String에 추가시켜주는 것이다
  • 또한, 갈 수 있는 곳을 다 갔을 때 그 값이 티켓 배열의 사이즈와 같다면 모든 곳을 방문해야한다는 조건을 만족하므로 답이 될 수 있는 list에 저장해둔다.
  • 공항의 수도 크지않고 dfs를 타기때문에 제곱보다 적은 시간이 사용되어 모든 가능성을 다 확인해서 list에 넣어도 시간초과는 뜨지않는다.
  • 또한 visit 배열을 하나만 가지고 재사용하기때문에, visit=true 후, dsf를 타고 나와서 다시 visit=false로 바꿔주어야한다.
  • 리스트 안에는 정답이 될 수 있는 “문자열들”이 들어있고, sort후 그 중 0번째를 가져오면 사전순으로 첫번째의 정답을 뽑아낼 수 있다.



이 문제를 풀면서 느낀점은 어떤 이어지는 값을 계속 가져가야할 경우에는 String에 계속 추가해서 넣어가면 간편하다는 것이다. 따라서, 매개변수를 잘 지정해주어야한다는 것을 다시한번 깨달을 수 있는 문제였다!!


아니 지킬의 문젠지 뭔지는 모르겠는데 왜 자꾸 씬텍스 에러뜨고

해결은 그냥 에러난 곳 괄호 두개였던 곳을 하나로 지워줬다… 왜…?

Read More

[백준] 케빈베이컨의 6단계 법칙 (java) Bfs

2020-03-20

케빈베이컨의 6단계 법칙 (백준>Dfs_Bfs )

문제 링크

문제설명

케빈 베이컨의 6단계 법칙에 의하면 지구에 있는 모든 사람들은 최대 6단계 이내에서 서로 아는 사람으로 연결될 수 있다. 케빈 베이컨 게임은 임의의 두 사람이 최소 몇 단계 만에 이어질 수 있는지 계산하는 게임이다.

예를 들면, 전혀 상관없을 것 같은 인하대학교의 이강호와 서강대학교의 민세희는 몇 단계만에 이어질 수 있을까?

천민호는 이강호와 같은 학교에 다니는 사이이다. 천민호와 최백준은 Baekjoon Online Judge를 통해 알게 되었다. 최백준과 김선영은 같이 Startlink를 창업했다. 김선영과 김도현은 같은 학교 동아리 소속이다. 김도현과 민세희는 같은 학교에 다니는 사이로 서로 알고 있다. 즉, 이강호-천민호-최백준-김선영-김도현-민세희 와 같이 5단계만 거치면 된다.

케빈 베이컨은 미국 헐리우드 영화배우들 끼리 케빈 베이컨 게임을 했을때 나오는 단계의 총 합이 가장 적은 사람이라고 한다.

오늘은 Baekjoon Online Judge의 유저 중에서 케빈 베이컨의 수가 가장 작은 사람을 찾으려고 한다. 케빈 베이컨 수는 모든 사람과 케빈 베이컨 게임을 했을 때, 나오는 단계의 합이다.

예를 들어, BOJ의 유저가 5명이고, 1과 3, 1과 4, 2와 3, 3과 4, 4와 5가 친구인 경우를 생각해보자.

1은 2까지 3을 통해 2단계 만에, 3까지 1단계, 4까지 1단계, 5까지 4를 통해서 2단계 만에 알 수 있다. 따라서, 케빈 베이컨의 수는 2+1+1+2 = 6이다.

2는 1까지 3을 통해서 2단계 만에, 3까지 1단계 만에, 4까지 3을 통해서 2단계 만에, 5까지 3과 4를 통해서 3단계 만에 알 수 있다. 따라서, 케빈 베이컨의 수는 2+1+2+3 = 8이다.

3은 1까지 1단계, 2까지 1단계, 4까지 1단계, 5까지 4를 통해 2단계 만에 알 수 있다. 따라서, 케빈 베이컨의 수는 1+1+1+2 = 5이다.

4는 1까지 1단계, 2까지 3을 통해 2단계, 3까지 1단계, 5까지 1단계 만에 알 수 있다. 4의 케빈 베이컨의 수는 1+2+1+1 = 5가 된다.

마지막으로 5는 1까지 4를 통해 2단계, 2까지 4와 3을 통해 3단계, 3까지 4를 통해 2단계, 4까지 1단계 만에 알 수 있다. 5의 케빈 베이컨의 수는 2+3+2+1 = 8이다.

5명의 유저 중에서 케빈 베이컨의 수가 가장 작은 사람은 3과 4이다.

BOJ 유저의 수와 친구 관계가 입력으로 주어졌을 때, 케빈 베이컨의 수가 가장 작은 사람을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 유저의 수 N (2 ≤ N ≤ 100)과 친구 관계의 수 M (1 ≤ M ≤ 5,000)이 주어진다. 둘째 줄부터 M개의 줄에는 친구 관계가 주어진다. 친구 관계는 A와 B로 이루어져 있으며, A와 B가 친구라는 뜻이다. A와 B가 친구이면, B와 A도 친구이며, A와 B가 같은 경우는 없다. 친구 관계는 중복되어 들어올 수도 있으며, 친구가 한 명도 없는 사람은 없다. 또, 모든 사람은 친구 관계로 연결되어져 있다.

출력

첫째 줄에 BOJ의 유저 중에서 케빈 베이컨의 수가 가장 작은 사람을 출력한다. 그런 사람이 여러 명일 경우에는 번호가 가장 작은 사람을 출력한다.

예제 입력 1 복사

5 5
1 3
1 4
4 5
4 3
3 2

예제 출력 1 복사

3


풀이

package Dfs_Bfs;

import java.util.*;
public class beak_케빈베이컨의6단계법칙 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n = sc.nextInt();
		int m = sc.nextInt();
		
		boolean connect[][] = new boolean[n+1][n+1];
		int cnt[] = new int[n+1];
		
		for(int i=0;i<m;i++) {
			int x = sc.nextInt();
			int y = sc.nextInt();
			
			connect[x][y] = connect[y][x] = true;
		}
		
		for(int i=1; i<=n; i++) {//다 넣어봐야 되니까
			Queue<Integer> q = new LinkedList<>();
			q.add(i);
			boolean visited[] = new boolean[n+1];
			int c[] = new int[n+1];
			visited[0] = visited[i] = true; // 1을 방문으로 해놓아야 하는게 아니고 i를 해놔야함
			
			while(!q.isEmpty()) {
				int x = q.poll();
				for(int j=1;j<=n; j++) {
					if(connect[x][j] && !visited[j]) {
						q.add(j);
						visited[j]= true;
						c[j] = c[x]+1; // 아 정신차리자 j도 i도 아닌 x잖아.....!
						cnt[i] += c[j];
					}
				}
			}//while
		}
		
		int min = Integer.MAX_VALUE;
		int idx = 0;
		
		for(int i=cnt.length-1; i>=1; i--) {
			if(min >= cnt[i]) {
				min = cnt[i];
				idx = i;
			}
		}
		
		System.out.println(idx);
	}
}

후기 (1h)

지금까지 bfs 어떻게 풀었나 싶다…ㅎ

그래도 연속 두 문제 풀면서, 감을 다시 익힐 수 있었다

연결돼있는 곳들을 전부 connect 배열에 넣고, 방문한 곳인지 아닌지는 visited 배열을 사용!

…하는 것 까지는 좋았으나, 자꾸 변수 넣는 부분에서 덤벙거려서 십몇분을 날려먹었다…!

Read More

[프로그래머스] 가장 먼 노드 (java) Bfs

2020-03-20

가장 먼 노드 (프로그래머스 > Dfs_Bfs)

문제 링크

문제설명

n개의 노드가 있는 그래프가 있습니다. 각 노드는 1부터 n까지 번호가 적혀있습니다. 1번 노드에서 가장 멀리 떨어진 노드의 갯수를 구하려고 합니다. 가장 멀리 떨어진 노드란 최단경로로 이동했을 때 간선의 개수가 가장 많은 노드들을 의미합니다.

노드의 개수 n, 간선에 대한 정보가 담긴 2차원 배열 vertex가 매개변수로 주어질 때, 1번 노드로부터 가장 멀리 떨어진 노드가 몇 개인지를 return 하도록 solution 함수를 작성해주세요.

제한사항
  • 노드의 개수 n은 2 이상 20,000 이하입니다.
  • 간선은 양방향이며 총 1개 이상 50,000개 이하의 간선이 있습니다.
  • vertex 배열 각 행 [a, b]는 a번 노드와 b번 노드 사이에 간선이 있다는 의미입니다.
입출력 예
n vertex return
6 [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] 3
입출력 예 설명

예제의 그래프를 표현하면 아래 그림과 같고, 1번 노드에서 가장 멀리 떨어진 노드는 4,5,6번 노드입니다.

image.png


풀이

0322.PNG

후기 (1h)

음.. 항상 연결되어있는 문제를 풀때는 인접행렬 방식으로 풀어왔는데, 그러면 항상 메모리 초과에 걸려서 코드를 고치는데 시간을 다쓰는 경우가 많았다.

따라서, 행렬을 사용하긴 하되, 배열을 전부 nXn을 만들어서 사용하지말고, 인접한 부분의 정보를 주는 크기만큼만 행렬을 만들고 그를 사용하기로 했다.

또한, 네트워크 문제처럼 가야하는 곳이 n개로 정해져있는 경우에는 visited[n]을 만들어 사용했던 것을 잊지말고 사용하자!

  • 전체 다 돌아보려고 하지말고, 최적을 구하려고 노력하자
  • 안그러면 다시 푸는데에 시간이 너무 오래걸린다…
  • 가끔 text를 인식 못하면 지우고 그냥 image로 바꿔 올리는데 뭐가 잘못된건지 모르겠다..으앙
Read More

[백준] 다리 놓기 (java) Dynamic_programming

2020-03-20

다리 놓기 (백준> Dynamic_programming)

문제 링크

문제설명

재원이는 한 도시의 시장이 되었다. 이 도시에는 도시를 동쪽과 서쪽으로 나누는 큰 강이 흐르고 있다. 하지만 재원이는 다리가 없어서 시민들이 강을 건너는데 큰 불편을 겪고 있음을 알고 다리를 짓기로 결심하였다. 강 주변에서 다리를 짓기에 적합한 곳을 사이트라고 한다. 재원이는 강 주변을 면밀히 조사해 본 결과 강의 서쪽에는 N개의 사이트가 있고 동쪽에는 M개의 사이트가 있다는 것을 알았다. (N ≤ M)

재원이는 서쪽의 사이트와 동쪽의 사이트를 다리로 연결하려고 한다. (이때 한 사이트에는 최대 한 개의 다리만 연결될 수 있다.) 재원이는 다리를 최대한 많이 지으려고 하기 때문에 서쪽의 사이트 개수만큼 (N개) 다리를 지으려고 한다. 다리끼리는 서로 겹쳐질 수 없다고 할 때 다리를 지을 수 있는 경우의 수를 구하는 프로그램을 작성하라.

img

입력

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 강의 서쪽과 동쪽에 있는 사이트의 개수 정수 N, M (0 < N ≤ M < 30)이 주어진다.

출력

각 테스트 케이스에 대해 주어진 조건하에 다리를 지을 수 있는 경우의 수를 출력한다.

예제 입력 1

3
2 2
1 5
13 29

예제 출력 1

1
5
67863915


풀이

package Dynamic_programming;

import java.util.*;
import java.math.BigInteger;

public class beak_다리놓기 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		
		for(int i=0;i<num;i++) {
			int n= sc.nextInt();
			int m = sc.nextInt();
			
			BigInteger sum =new BigInteger("1");
			
			int temp = n;
			while(temp>0) {
				sum = sum.multiply(BigInteger.valueOf(m));
				m--;
				temp--;
			}
			
			while(n>0) {
				sum = sum.divide(BigInteger.valueOf(n));
				n--;
			}
			
			System.out.println(sum);
		}
		
	}
}

후기 (25 min)

m개의 다리중에 n개를 놓을 수 있는 Combination문제였다!!!!

  • mCn일 때!

  • 5C3이면 5x4x3 / 3x2x1
  • 5C2이면 5x4/2x1

하지만,, 큰 숫자가 들어올 수 도 있기 때문에

long으로도 답이 틀렸다고 나오길래, BigInteger()라는 클래스를 사용해서 해결했다!
import java.math.BigInteger;

main(){
    	int n; int m;
		BigInteger sum = new BigInteger("1");	   //bigInteger sum
		sum = sum.multiply(BigInteger.valueOf(m)); // sum에 m곱하기
    	sum = sum.divide(BigInteger.valueOf(n));   // sum에 n나누기
}
Read More