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

이현진 / 10월 3주차 / 목 #284

Merged
merged 1 commit into from
Oct 23, 2023
Merged

Conversation

hgene0929
Copy link
Contributor


🎈boj 17297 - MessiGimossi


🗨 해결방법 :

(1) m(구해야하는 문자의 자릿수)을 초과하는 문자열을 규칙에 따라 생성
(2) 분할과 정복을 통해 필요없는 문자열은 잘라서 버려가면서 재귀 호출

📝메모 :

  • m을 초과하는 문자열 생성 방식은 moo 문제와 같이 재귀함수 내부에서 만들어가면서 풀이하면 시간초과가 났습니다.
    • 그래서 메모리를 잡아먹더라도, 재귀 호출 전에 자릿수만 규칙에 따라 저장후 풀이하였습니다.
  • 중간(' ') 자릿수와 일치하는 m의 경우에는 바로 Messi Messi Gimossi 를 반환하여 시간을 조금 줄여보려 했습니다.

✔코드 :

public class boj17297_MessiGimossi {
	static int M;
	static List<Integer> len = new ArrayList<>();

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		// input
		M = Integer.parseInt(br.readLine());

		// solution
		// m 길이를 초과하는 문자열을 생성
		len.add(0);
		len.add(5);
		len.add(13);
		int prev = len.get(1), now = len.get(2), total = 0;
		while(true) {
			total = now+1+prev;
			len.add(total);
			if(total > M) break;
			prev = now; now = total;
		}
		// messi(N)의 M 번째 글자 구하기
		String res = findM(M, len.size());

		// output
		System.out.println(res);
	}

	static String findM(int m, int n) {
		// 기저조건 : messi(1), messi(2) 둘 중에 하나여야 함
		if(m <= 13) return letter(m);

		// 풀이 : m 이 왼쪽(messi(K-1)), 중간(' '), 오른쪽(messi(K-2)) 중 어디에 속하는지 확인
		if(m <= len.get(n-1)) { // n 이 왼쪽(messi(K-1)) 범위에 있음
			return findM(m, n-1);
		} else if(m == len.get(n-1)+1) { // n 이 중간(' ') 범위에 있음
			return "Messi Messi Gimossi";
		} else { // n 이 오른쪽(messi(K-2)) 범위에 있음
			return findM(m-(len.get(n-1)+1), n-2);
		}
	}

	static String letter(int m) {
		switch(m) {
			case 1:
				return "M";
			case 2:
				return "e";
			case 3:
			case 4:
			case 11:
			case 12:
				return "s";
			case 5:
			case 8:
			case 13:
				return "i";
			case 7:
				return "G";
			case 9:
				return "m";
			case 10:
				return "o";
		}
		return "Messi Messi Gimossi";
	}
}


🎈boj 15989 - 1,2,3 더하기 4


🗨 해결방법 :

(1) 주어진 재료별로(1, 2, 3) 반복하면서
(2) 1~N(목표치) 까지를 로직을 적용하여
(3) 이전값(한번 정해진 값은 fix 됨을 파악하였습니다)을 활용하여 다음 값을 도출해내었습니다 => DP

📝메모 :

이러한 DP(배낭문제)의 경우 다음과 같이 3가지로 구분해보았습니다.
(1) 재료들의 개수가 무한한 경우 : 1차원 DP 하나만을 통해 목표치까지 순차적으로 로직을 적용
(2) 재료들의 개수가 1개인 경우 : 1차원 DP 하나만을 통해 목표치까지 로직을 적용하되, 이전의 값이 갱신되는 문제해결을 위해 뒤에서부터 로직 적용
(3) 재료들의 개수가 N개인 경우 : 1차원 DP 2개(참조용, 갱신용)를 두어 갱신용에 값을 저장하고, 재료들을 바꿀 때마다 참조용 DP 에 갱신용 DP를 복사

✔코드 :

public class boj15989_123더하기4 {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();

		int T = Integer.parseInt(br.readLine());
		for(int t=1; t<=T; t++) {
			// input
			int N = Integer.parseInt(br.readLine());

			// solution
			int[] dp = new int[N+1];
			dp[0] = 1;

			for(int i=1; i<=3; i++) { // 주어진 재료별로(1,2,3)
				for(int j=1; j<=N; j++) { // 1~N 까지의 목표치를
					if(j-i >= 0) dp[j] += dp[j-i]; // 이전값을 이용해가면서 갱신
				}
			}

			// output
			sb.append(dp[N]).append("\n");
		}

		System.out.println(sb.toString());
	}
}


🎈boj 2661 - 좋은수열


🗨 해결방법 :

  • 주어진 자릿수를 만족할 때까지 "" 문자열을 -> 좋은수열의 조건을 만족하는 문자열로 문자 하나씩 더해나감
    • 현재 상황에서 가능한 문자열을 우선 이어붙인 다음 재귀함수를 통해 조건을 만족하는지 검사 => 백트래킹
    • 만족한다면 -> 다음 문자 구하러 재귀호출
    • 만족하지 않는다면 -> 재귀호출 X(함수종료)

📝메모 :

  • 백트래팅.. 파이팅!!!

✔코드 :

public class boj2661_좋은수열 {
	static int N;

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		// input
		N = Integer.parseInt(br.readLine());

		// solution & output
		backtrack("");
	}

	/**
	 * 파라미터로 받은 숫자(이전까지 만들어진 숫자)에 새로운 숫자를 더할건데,
	 * 이때 이전의 숫자와 동일한 숫자는 제외
	 */
	static void backtrack(String num) {
		// 기저조건 : 주어진 자릿수(N)만큼의 숫자길이를 완성하면 반환
		if(num.length() == N) {
			System.out.println(num);
			System.exit(0);
		}

		// 풀이 :
		// 이전까지 만든 숫자와 중복되는지 확인(길이만큼 : 1자리 비교, 2자리 비교, ... 길이/2 자리 비교)
		// 중복되지 않으면 다음 숫자 만들러 감(재귀호출)
		for(int i=1; i<=3; i++) {
			if(check(num+i)) backtrack(num+i);
		}
	}

	static boolean check(String num) {
		if(num.length() == 1) return true;
		int len = num.length();
		for(int i=1; i<=len/2; i++) { // 1자리수 비교, 2자리수 비교, ... N/2자리수 비교
			boolean duplicated = true;
			for(int j=0; j<i; j++) {
				if(num.charAt(len-2*i+j) != num.charAt(len-i+j)) {
					duplicated = false;
				}
			}
			if(duplicated) return false;
		}
		return true;
	}
}

@hgene0929 hgene0929 merged commit b036de9 into SSAFY-10th-Seoul17:main Oct 23, 2023
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants