첫 번째로 푼 풀이 + 두 번째로 다시 풀어볼 때의 풀이가 추가되었다.
(2:25... ㅋㅋㅋㅋㅋㅋ)
채널 N으로 이동하기 위해, [ 버튼을 최소 몇 번 ] 눌러야 하는지 구하는 프로그램 작성하기
누를 수 있는 숫자 버튼이 5 만 있다하고, target이 500이면
- 555로 이동후 -를 55번 하는게.
- +를 400번 하는 것 보다 덜 든다.
target이 101이면
- 숫자로 101을 누르면 -> 3개의 버튼을 누르는 것
- + 버튼을 한 번 누르기 -> 1개읩 버튼을 누르는 것
target이 98이면
- 숫자로 98 누르면 -> 2개의 버튼
- - 버튼 두 번 -> 2 개의 버튼 누르기
이외의 경우가 있나??
선택의 경우
주어진 숫자버튼으로 target과 최대한 가까운 숫자 만들기 → ??? 아무래도 모든 경우의 숫자들에 대해 해 보아야 할 것 같다.
완전탐색? → 완전탐색으로 풀어도 괜찮은 편이다.
생각하고 있는 완전탐색 :
이러한 완전탐색이 가능한가? YES
현재 n의 제한 : 50만: 500000 -> 6자리수.
100만을 넘는 경우는 조사할 필요가 없다.
따라서 만약 n이 6자리수라면 -> 10000 부터 999999 까지만 조사하면 되기 때문에
완전탐색을 해도 100만을 넘지를 않는다.
왜 n-1자리도, n+1자리도 봐야하는가?
target이
1. 999 인 경우 (n+1자리도 봐야하는 이유)
주어진 수가 1과 0만 있다면
1000을 만드는게
111을 만드는 것보다 더 좋을 거임.
따라서, target의 자리수 m 이라고 하면
m-1자리수 ~ m+1자리수를 모두 만들어 봐야 하나
- 만들어 볼 것인가
아니면
- m-1자리수 가장 작은 숫자 ~ max 숫자 해서, 각 자릿수에 고장난 번호가 있으면 그 번호를 버리기를 할 것인가
----> 최대..5자리수 10000~ 99999
-----> 6자리수 : 100000~ 999999
--최대 50만이니, 100만 넘는 거는 안 봐도됨
2. target이 10000 인 경우인데 버튼 0이 고장나있는 경우
9999 에서 +1을 하는게 더 낫기 때문임.
이 문제에서는, 자리수를 직접 구하는 함수를 작성하는게 중요한 것 같다.
package cote;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
/*
* 1 10
* 1+ 1 = 2 -> 4 -> 8
* 1 2 4 8 -> 9, 10
*
*
* */
public class Main{
/*
* Integer형태로 10000 부터 99999 까지 검사하기를 하면
* 해당 int에 대한 연산을 수행 해야 한다. 그게 낫겠다
* */
public static int resMin = Integer.MAX_VALUE;
public static int n,m;
public static boolean[] numbers = new boolean[10];// 0~ 9 까지의 버튼
public static boolean[] op = new boolean[2]; // +1, -1
public static void Setting() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
m = Integer.parseInt(br.readLine());
Arrays.fill(numbers,true);
Arrays.fill(op,true);
// 가능한 버튼정보를 어떻게 넣을까? -> char 형태로?
// +와 -가 있어서..
// 아니면 그냥 boolean table을 생성하여, 고장났는지 여부를 표시? -> 이 방법을 택함
if(m>0){
String nots = br.readLine();
String[] disabled = nots.split(" ");
for(String s : disabled) {
// 고장난 버튼은 -일 수도 +일 수도 있다.고 생각했다.
try {
int numb = Integer.parseInt(s);
numbers[numb]=false;
}catch(NumberFormatException e){
if(s.equals("+")){
op[0]=false;
}else{
op[1]=false;
}
}
}
}
}
public static void solve(){
int simplecnt =Integer.MAX_VALUE;
int numbcnt =Integer.MAX_VALUE;
int tempCnt= Integer.MAX_VALUE;
// 단순히 +나 - 연산으로 구할 수 있는 경우.
if(n==100) {
resMin =0;
return;
}
else if(n>100&&op[0]){ // n 이 100보다 크고, + 연산자가 고장나지 않은 경우
simplecnt = n-100;
}else if(n<100 && op[1]) simplecnt=100-n; // n이 100보다 작고, -연산자가 고장나지 않은 경우
tempCnt = simplecnt;
// n은 0이상 50만 이하일 수 있다.
String temp = Integer.toString(n);
// target의 자리수를 구한다.
int len = temp.length();
// target의 후보인 수들의 '자리수'를 초기화한다.
int len_min =len,len_max = len;
int min=0,max=0;
// 500000
if(len == 6){
// len-1 자리 부터 len 자리까지
len_min = len -2;
len_max = len;
}else{
// len-1 자리부터 len + 1 자리까지
len_min = len-2;
len_max = len+1;
}
// 만약 len 이 한 자리 수 -> min은 0부터 해야함
if(len_min<=0) min =0;
else{
min = (int)Math.pow(10,len_min);
}
// len_max = 5 면 99999 해야하니
// len_max = 6 이면 999999 으로 해야 하니
max = (int)Math.pow(10,len_max)-1;
// min부터 max까지의 정수들에 대해 완전탐색한다.
for(int i=min;i<=max;i++){
// i라는 숫자가 '숫자버튼을 눌러' 만들 수 있는 것인지 확인한다.
if((numbcnt=splitNumber(i))==Integer.MAX_VALUE) continue;
// i가 만들 수 있는 숫자인 경우 -> i에서 n 까지 몇 번의 + or - 연산을 해야하는지 구한다.
if(n==i) numbcnt+=0;
else if(n>i&&op[1]){
numbcnt+= (n-i);
}else if(n<i && op[0]) numbcnt+=(i-n);
// 구해진 numbcnt와 tempCnt를 비교한다. tempCnt는 simpleCnt(+로만 or -로만했을 때의 count개수)로 초기화되어있다.
tempCnt=Math.min(tempCnt,numbcnt);
}
// 버튼으로 숫자를 만들 수는 없는 경우, simpleCnt가 최소가 될테니 for문 밖에서도 Resmin을 업데이트 해줘야한다.
tempCnt=Math.min(tempCnt,numbcnt);
resMin=Math.min(resMin,tempCnt);
}
//최대 6번의 연산을 한다
// a_n의 정수의 각 자리수를 확인하여, 각 자리에 있는 숫자가 고장난 버튼인지확인한다.
public static int splitNumber(int a_n){
int res = Integer.MAX_VALUE;
int len = (int)Math.log10(a_n) +1;
if(a_n==0) len = 1;
// 구성요소중 고장 난 버튼이 있는지 체크한다.
int next =a_n;
int cur=0;
int mul=(int)Math.pow(10,len-1);
while(mul>9){
cur = next/mul;
if(numbers[cur]==false)return res;
next-= (cur*mul);
mul/=10;
}
cur = next%10;
if(numbers[cur]==false)return res;
return len;
}
public static void main(String[] args) throws IOException {
Setting();
solve();
System.out.println(resMin);
}
}
그랬다..
(0:40)
0~9 버튼 중 고장나는 버튼이 주어진다. → 해당 버튼은 누를 수 없다.
0 번에서 - 버튼을 누르면 채널은 변하지 않는다.
N번으로 이동하려 한다.
N번으로 이동하기 위해 버튼을 최소 몇 번 눌러야 하는가???
현재 채널은 100번이다.
N은 0이상 50만 이하이다.
고장 난 버튼의 개수는 0 이상 10 이하 → 모든 숫자 버튼이 고장 날 수도 있다.
두 가지 경우를 생각 해 볼 수 있다.
주어진 숫자 버튼 중, N번에 가까운 숫자를 만들어야 한다.
특정 숫자를, 현재 수자들을 조합해서 만들 수 있는가 ?
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main{
public static int n;
public static int m;
public static int min = Integer.MAX_VALUE; // 5000000 으로 해두 되겠다.
public static boolean[] broken = new boolean[10]; //고장난 버튼 -> false
public static void Setting() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int temp=0;
n = Integer.parseInt(br.readLine());
m = Integer.parseInt(br.readLine());
Arrays.fill(broken,true); //모두 true로 초기화
if(m>0) {
st = new StringTokenizer(br.readLine());
for (int i = 0; i < m; i++) {
temp = Integer.parseInt(st.nextToken());
broken[temp] = false;
}
}
}
public static void solve(){
if(n==100) {
min = 0;
return;
}
// +, -만을 이용하여 이동하는 경우를 생각하기.
// 현재는 100번에 위치하고 있다. N번과의 차이를 절댓값으로 구한다.
min = Math.abs((100-n));
int cnt=0;
//완전탐색을 한다.
for(int t=0;t<=1000000;t++){
// t라는 채널로 이동가능한 경우 -> (100->t ) + ( t-> N ) 의 수를 계산하여 min 과 비교한다.
if((cnt=isPossible(t))<0)continue;
// 100 -> t 로 가는데 버튼은 cnt 번 누른다.
// t- > N 으로 가는데에는 이제 +,- 만을 이용한다.
cnt += Math.abs((t-n));
min = Math.min(min,cnt);
}
}
// t라는 숫자를 현재 생성 가능한지 살펴본다 + 생성가능한 경우, t의 자리수를 리턴한다.
public static int isPossible(int t){
// 각 자리수를 구한다.
int cur =t;
int num = 0;
int cnt =1;
// 1의 자리 수 부터 확인한다.
while(true){
num = cur % 10 ;
if(broken[num]==false) return -1;
cur /=10;
if(cur ==0) break;
cnt++;
}
return cnt;
}
public static void main(String[] args) throws IOException {
Setting();
solve();
System.out.println(min);
}
}