# 공부를 위해 정리하는 글이므로, 정확하지 않을 수 있습니다. 지적은 언제나 감사합니다.

 

 

<연습문제>

다음과 같은 main.json 파일을 파싱해 테이블 뷰 custom cell에 띄우기

[{    "detail_hash": "HBDEF",    "image": "http://public.codesquad.kr/jk/storeapp/data/2d3f99a9a35601f4e98837bc4d39b2c8.jpg",    "alt": "[미노리키친] 규동 250g",
    "delivery_type": ["새벽배송", "전국택배"],
    "title": "[미노리키친] 규동 250g",
    "description": "일본인의 소울푸드! 한국인도 좋아하는 소고기덮밥",
    "n_price": "6,500",
    "s_price": "7,000원",
    "badge": ["이벤트특가"]
  },
  {
    "detail_hash": "HDF73",
    "image": "http://public.codesquad.kr/jk/storeapp/data/7674311a02ba7c88675f3186ddaeef9e.jpg",
    "alt": "[빅마마의밥친구] 아삭 고소한 연근고기조림 250g",
    "delivery_type": ["새벽배송", "전국택배"],
    "title": "[빅마마의밥친구] 아삭 고소한 연근고기조림 250g",
    "description": "편식하는 아이도 좋아하는 건강한 연근조림",
    "s_price": "5,500원"
  },
 
 ...

 


 

1. 파싱한 내용을 담을 객체 생성하기

  • 이때 객체 타입에 따라 편하게 담기 위해, 클래스에 Codable을 채택한다.

struct StoreItem : Decodable {
    var detail_hash : String?
    var image : String?
    var alt : String?
    var delivery_type : [String]?
    var title : String?
    var description : String?
    var n_price : String?
    var s_price : String?
    var badge : [String]?
}
  • json 파일에 특정 변수가 있는 경우, 없는 경우가 모두 있기 때문에 optional로 변수를 지정해주어야 한다.
    (옵셔널로 해주지 않으면 데이터가 제대로 들어가지 않음)

2. Json 파일을 파싱해 StoreItem 배열에 저장해준다.

  • 해당 path에서 json 파일을 string 으로 가져오고,

  • json String 을 data 타입으로 변경한 다음, JSONDecoder를 이용해 인스턴스에 저장한다.

    func loadData(){
        if let filePath = Bundle.main.path(forResource: "main", ofType: "json"){
            let decoder = JSONDecoder()
            let content = try! String(contentsOfFile: filePath)
            var data = content.data(using: .utf8)
            menuItemArray = try? decoder.decode(Array<StoreItem>.self, from: data!)
        }else {
            print("파일이 존재하지 않습니다.")
        }
    }

 

3. 원하는 디자인으로 커스텀 셀을 만들어준다.

 

4. 커스텀셀 파일을 생성하고, MainViewController의 테이블뷰 메서드에 파싱한 객체의 값을 넣어준다.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MenuCell", for : indexPath) as! MenuItemCell
        
        cell.menuTitle.text = menuItemArray?[indexPath.row].title
        cell.menuSubscrib.text = menuItemArray?[indexPath.row].description
        cell.menuPrice_n.text = menuItemArray?[indexPath.row].n_price
        cell.menuPrice_s.text = menuItemArray?[indexPath.row].s_price

        return cell
    }

 

 

결과화면은 다음과 같다.

 

# 공부를 위해 정리하는 글이므로, 정확하지 않을 수 있습니다.

  • Codable이란?

    • A type that can convert itself into and out of an external representation."

      자신을 변환하거나 외부표현(external representation)으로 변환할 수 있는 타입

    • 즉, 특정 객체가 Codable 프로토콜을 채택하면, 해당 객체는 'json'과 같은 외부 타입으로 인코딩과 다시 json에서 객체로 디코딩이 가능하게 된다.

  • Codable 객체를 json으로 인코딩하기

    • 아래는 json으로 encoding한 예제이다. (Person객체 -> json)

      1. 인스턴스를 data 타입으로 인코딩

      2. data타입을 json 타입으로 변경

 func codableTest() {
        
        struct Person : Codable{
            var name : String?
            var age : Int
        }
        
        let encoder = JSONEncoder()
        let object = Person(name: "zeze", age: 7)
        let jsonData = try? encoder.encode(object)
        
        if let jsonData = jsonData, let jsonString = String(data: jsonData, encoding: .utf8){
            print(jsonString) //{"name":"Zedd","age":100}
        }

}

  

  •  
  • json을 인스턴스타입으로 파싱하기 ( jsonStr ➔ Data ➔ Object )

    • 받아온 json을 인스턴스로 파싱하는 것이 더 자주 사용되는 방식

    • 인코딩했던것과 반대방법으로

      1. json을 읽어 json String 값으로 저장

      2. json String 타입을 data타입으로 변경

      3. data타입인스턴스로 디코딩

func codableDecoding(jsonStr : String){

  	let decoder = JSONDecoder()
    var data = jsonStr.data(using: .utf8) // json형식을 Data타입으로 변경
    // data타입을 인스턴스 타입으로 변경
    if let data = data, let myPerson = try? decoder.decode(Person.self, from: data){
    	print(myPerson.name) //Zedd
      print(myPerson.age)
    }
}
  •  

 

 

※ json 파일을 json string으로 읽어오기

  1. 파일 경로 가져오기

  2. 파일경로로 json String 가져오기

let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
let content = try! String(contentsOfFile: filePath!)

 

menuItemArray 에 데이터가 들어간 모습

 

# 공부를 위해 정리하는 글이므로, 정확하지 않을 수 있습니다.

 

처음 delegate의 개념을 접했을 때, 안드로이드의 calback 메서드와 어떤게 다른지 이해가 잘 되지 않았다.

 

'델리게이트는 단순하게 어느 누군가가 너에게 변화를 알릴때, 너 자신을 다른자신에게 넘기는 것을 말한다. 그래서 너는 그들에게 반응하게 된다. 예를 들어, 만약 ViewController가 네트워크 서비스에게 얘기할 때, 그리고 그 서비스가 어떤 요청을 끝냈을 때 알림받기를 원할 때 이것은 그것 자체로 네트워크 서비스의 델리게이트가 된다. 그리고 이것을 끝마쳤을 때 네트워크 서비스는 델리게이트를 호출할 것이다.'

 

'callback은 델리게이트 패턴과 기능면에서 유사하다. 이것은 어떤 일이 발생했을 때 다른 객체가 이를 알도록 하며, 데이터를 넘긴다는 것이 동일하다. 델리게이트 패턴이 자신의 참조를 넘기는 대신에, 콜백 메서드는 함수를 넘긴다는 것이다. 함수는 swift의 일등시민이므로 니가 함수 속성을 가질 어떤 이유도 없다.'

[JAVA] 백준 1986 : 체스

문제


주어진 NxM의 체스판에 Knight, Queen, Pawn이 주어질 때, 이 말들을 움직였을 때 잡힐 수 없는 안전한 칸의 개수를 구하는 문제

Knight : 2x3의 직사각 형을 만들 었을 때, 해당 점에서 가장 먼 점으로만 이동할 수 있다. 중간에 다른 말이 있어도 영향을 받지 않는다.

Queen : 가로, 세로, 대각선으로 쭉 움직일 수 있다. 단, 중간에 다른 말이 있다면 그 전까지만 이동할 수 있다.

Pawn : 움직이지 못하고 그저 장애물 역할만 한다.



접근방법


주어진대로 노가다 코드를 짜면 얼마든지 해결할 수 있다.


즉, 먼저 Queen이 갈 수 있는 범위를 체크하고, 그 다음으로 Knight가 갈 수 있는 범위를 체크하고, 해당 말 들이 없는 칸들의 개수를 세서 출력해주면 된다.

  1. 먼저 queen, knight의 위치를 ArrayList에 저장하고, char배열인 맵의 해당 위치에 각 말의 알파벳(K, Q, P)을 넣어준다.

  2. 각 queen, knight를 정해진 규칙에 따라 이동하도록 하고, 이동한 좌표는 'o'로 바꾸어 준다.

  3. 각 말들이 이동하지 않은 곳은 char의 초기값인 '\u0000'이 들어있으므로, 이러한 원소들의 개수를 확인해 출력해준다.


같은 스터디원의 코드를 참고해 더 깔끔하게 코드를 수정해 보았다.

  1. dx, dy 배열을 이용하면 규칙이 없더라도 for문으로 돌릴 수 있다.

    • 예를 들어 위, 아래, 오른쪽, 왼쪽, 왼쪽위, 오른쪽위, 왼쪽아래, 오른쪽아래를 확인해야 하는 Queen의 경우에는 dx, dy 배열을 이용해 아래와 같이 코드를 짤 수 있다.

      for(int i=0; i<8; i++){
         int next_x = x;
         int next_y = y;
         while(true) {
             next_x += dx[i];
             next_y += dy[i];

             if(next_x < 0 || next_x >= N || next_y < 0 || next_y >= M)
                 break;  // map 범위를 벗어나는 경우
             if(map[next_x][next_y] == 'K'
                     || map[next_x][next_y] == 'Q'
                     || map[next_x][next_y] == 'P' )
                 break;  // 말이 지나갈 수 없는 경우(K/P/Q)

             map[next_x][next_y] = 'o';
        }
      }
    • knight의 움직임 경우에는 아래와 같이 코드를 짤 수 있다.

      int[] dx = {2, 2, 1, 1, -1, -1, -2, -2};
      int[] dy = {1, -1, 2, -2, 2, -2, 1, -1};

      for(int i=0; i<8; i++){
         int next_x = x + dx[i];
         int next_y = y + dy[i];

         if(next_x >= 0 && next_x < N
                 && next_y >=0 && next_y < M){   // 배열 범위 내에 있으면서
             if(map[next_x][next_y] == '\u0000') // 빈칸일 경우
                 map[next_x][next_y] = 'o';
        }
      }

소스코드

    static int N, M;
   static char[][] map;

   static class Pos{
       int x; int y;
       public Pos(int x, int y) {this.x = x; this.y = y;}
  }

   static void checkQueen(int x, int y){

       int[] dx = {1, -1, 0, 0, 1, 1, -1, -1};
       int[] dy = {0, 0, 1, -1, 1, -1, 1, -1};

       for(int i=0; i<8; i++){
           int next_x = x;
           int next_y = y;
           while(true) {
               next_x += dx[i];
               next_y += dy[i];

               if(next_x < 0 || next_x >= N || next_y < 0 || next_y >= M)
                   break;  // map 범위를 벗어나는 경우
               if(map[next_x][next_y] == 'K'
                       || map[next_x][next_y] == 'Q'
                       || map[next_x][next_y] == 'P' )
                   break;  // 말이 지나갈 수 없는 경우(K/P/Q)

               map[next_x][next_y] = 'o';
          }
      }
  }

   static void checkKnight(int x, int y){
       int[] dx = {2, 2, 1, 1, -1, -1, -2, -2};
       int[] dy = {1, -1, 2, -2, 2, -2, 1, -1};

       for(int i=0; i<8; i++){
           int next_x = x + dx[i];
           int next_y = y + dy[i];

           if(next_x >= 0 && next_x < N
                   && next_y >=0 && next_y < M){   // 배열 범위 내에 있으면서
               if(map[next_x][next_y] == '\u0000') // 빈칸일 경우
                   map[next_x][next_y] = 'o';
          }
      }
  }

   public static void main(String[] args) throws IOException{

       BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

       String[] input = in.readLine().split(" ");
       N = Integer.parseInt(input[0]);
       M = Integer.parseInt(input[1]);

       map = new char[N][M];

       ArrayList<Pos> queen = new ArrayList<>();
       ArrayList<Pos> knight = new ArrayList<>();

       // input
       for(int i=0; i<3; i++){
           input = in.readLine().split(" ");
           int num = Integer.parseInt(input[0]);

           for(int j=1; j<=num; j++){
               int x = Integer.parseInt(input[2*j-1]) - 1;
               int y = Integer.parseInt(input[2*j]) - 1;

               if(i==0){
                   queen.add(new Pos(x,y));
                   map[x][y] = 'Q';
              }else if(i==1){
                   knight.add(new Pos(x,y));
                   map[x][y] = 'K';
              }else{
                   map[x][y] = 'P';
              }
          }
      }

       // queen check
       for(int i=0; i<queen.size(); i++)
           checkQueen(queen.get(i).x, queen.get(i).y);


       // knight check
       for(int i=0; i<knight.size(); i++)
           checkKnight(knight.get(i).x, knight.get(i).y);

       int answer = 0;
       for(int i=0; i<N; i++)
           for(int j=0; j< M; j++)
               if(map[i][j] == '\u0000')
                   ++answer;

       System.out.println(answer);
  }

'알고리즘' 카테고리의 다른 글

[JAVA] 백준 1406 : 에디터  (0) 2019.02.16
[JAVA] 백준 1347 : 미로만들기  (0) 2019.02.06
[JAVA] 백준 2512 : 예산  (0) 2019.02.02
[JAVA] 백준 3985 : 롤케이크  (0) 2019.02.01
[JAVA] 백준 10610 : 30  (0) 2019.02.01

[JAVA] 백준 1406 : 에디터


문제

명령어를 받아 문자열을 수정하는 에디터를 작성하는 문제. 처음 문자열과 명령어 개수, 명령어 L, D, B, P $가 입력된다. 커서를 이용해 문자열을 수정하는데, 처음 커서는 문자열의 맨 뒤에 있다. L의 경우에는 커서를 왼쪽으로 하나, D의 경우에는 커서를 오른쪽으로 하나, B는 커서의 왼쪽 문자를 삭제하고, P ~ 의 경우에는 해당 문자를 커서 뒤에 추가해준다. 커서는 보통 컴퓨터에서 움직이는 것 처럼 움직인다.


처음 접근방법

cursor를 String의 인덱스로 이용해 문제 그대로 구현하였고, 시간초과가 났다. StringBuffer을 이용해도 시간초과가 났기 때문에 구현하는 방법을 바꿔야 했다.


수정된 접근방법

  • 스택 2개를 이용한다.

    • 커서를 스택 A의 pop위치라고 두고, 스택 B는 커서 뒤에 있는 문자를 저장한다.

    • 명령어 수행 방법

      • L : 스택 A를 스택 B로 옮긴다. stack_B.push(stack_A.pop());

      • 명령어 D : 스택 B를 스택 A로 옮긴다. stack_A.push(stack_B.pop());

      • 명령어 B : 스택 A를 pop 해준다.

      • 명렁어 P : 스택 A에 문자를 push 해준다.

    • 여기서 stack이 비어있을 경우를 꼭 확인해 주어야한다.




소스코드

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String text = in.readLine();
int N = Integer.parseInt(in.readLine());

Stack<Character> stack = new Stack<>();
Stack<Character> stack_tmp = new Stack<>();

for(int i=0; i<text.length(); i++)
stack.push(text.charAt(i));

for(int i=0; i<N; i++){
String cmd = in.readLine();

if(cmd.charAt(0) == 'L'){
if(!stack.isEmpty())
stack_tmp.push(stack.pop());
}else if(cmd.charAt(0) == 'D'){
if(!stack_tmp.isEmpty())
stack.push(stack_tmp.pop());
}else if(cmd.charAt(0) == 'B'){
if(!stack.isEmpty())
stack.pop();
}else if(cmd.charAt(0) == 'P'){
stack.push(cmd.charAt(2));
}
}

while(!stack_tmp.isEmpty()){
stack.push(stack_tmp.pop());
}

StringBuilder answer = new StringBuilder();
while(!stack.isEmpty()){
answer.append(stack.pop());
}

System.out.println(answer.reverse().toString());





'알고리즘' 카테고리의 다른 글

[JAVA] 백준 1986 : 체스  (0) 2019.02.21
[JAVA] 백준 1347 : 미로만들기  (0) 2019.02.06
[JAVA] 백준 2512 : 예산  (0) 2019.02.02
[JAVA] 백준 3985 : 롤케이크  (0) 2019.02.01
[JAVA] 백준 10610 : 30  (0) 2019.02.01

문제

홍준이는 미로의 남쪽을 보면서 서 있으며 명령에 따라 움직인다. F가 나오면 해당 방향으로 이동하고, R이나 L이 나오면 현재 방향을 기준으로 왼쪽이나 오른쪽으로 방향을 바꾼다. 명령에 따라 움직인 것은 미로에서 갈 수 있는 모든 곳이라고 했을 때, 갈 수 있는 길은 '.'로, 갈 수 없는 길은 '#'로 미로를 출력한다.



접근방법

  1. 처음 좌표를 (0,0)으로 두고, 이동한 좌표를 저장한다.

    • 현재 방향을 direct로 두고, 방향 명령어(R, L)이 나오면 이 방향을 바꿔준다.

    • 이동 명령어(F)가 들어오면 현재 위치를 기준으로 해당 방향으로 이동한 좌표를 리스트에 저장한다.

      ex) 현재 좌표 (0, 1)이며 현재 방향이 위쪽일 때 이동명령어(F)가 들어오면 (-1, 1) 좌표를 만들어 저장한다.

  1. x, y 각각의 max, min 값을 저장 한 뒤, 이 값을 이용해 배열의 크기를 정한다.

    • (0, 0), (-1, 0), (-1, 1) 로 이동했다고 할 때, 만들어지는 배열의 크기는 (max_x - min_x + 1) * (max_y - min_y + 1)이 된다.

    • 주어진 조건에서 '모든 행과 열에는 적어도 하나의 이동할 수 있는 칸이 있다'고 했으므로, 이동한 칸을 중심으로 배열을 만들고 그 중에서 이동하지 않은 칸은 벽('#')으로 채워주면 된다.

    • int[][] map = new int[max_x - min_x + 1][max_y - min_y + 1];
  2. 이동한 좌표의 가장 왼쪽 위의 값을 (0, 0)으로 바꾸어 배열에 넣는다.

    • 처음 (0, 0) 을 기준으로 상대좌표를 저장하고 있기 때문에, 모든 좌표에서 min_x를 0으로, min_y를 0으로 만들면 가장 작은 값이 왼쪽 위가 되므로 절대 좌표로 바꾸어준다.

      for(int i=0; i<poses.size(); i++){
         int x = poses.get(i).x + (-1 * min_x);
         int y = poses.get(i).y + (-1 * min_y);
         map[x][y] = 1;
      }
  1. 이동한 좌표를 배열에 표시한 다음, 주어진 출력 형식에 맞춰 출력한다.



소스코드

static class Pos{
   int x; int y;
   public Pos(int x, int y) {this.x = x; this.y = y;}
}

static Pos cur_pos;
static int direct; // 방향 : 위(0), 오른(1), 아래(2), 왼(3)

// 방향 회전
static void rotate(char dir){
   if(dir == 'R'){
       ++direct;
       if(direct > 3)
           direct = 0;
  }else if(dir == 'L'){
       --direct;
       if(direct < 0)
           direct = 3;
  }
}

public static void main(String[] args) throws IOException{
   BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
   int N = Integer.parseInt(in.readLine());
   String command = in.readLine();

   cur_pos = new Pos(0,0); // 처음 좌표 : (0, 0)
   direct = 2; // 처음 방향 : 남쪽

   ArrayList<Pos> poses = new ArrayList<>();
   poses.add(new Pos(0,0));

   int min_x, min_y, max_x, max_y;
   min_x = min_y = max_x = max_y = 0;

   for(int i=0; i<N; i++){
       // 해당 방향으로 이동
       if(command.charAt(i) == 'F'){
           if(direct == 0)
               --cur_pos.x;
           else if(direct == 1)
               ++cur_pos.y;
           else if(direct == 2)
               ++cur_pos.x;
           else if(direct == 3)
               --cur_pos.y;

           poses.add(new Pos(cur_pos.x, cur_pos.y));

           // 최대값-최솟값 저장
           if(cur_pos.x > max_x) max_x = cur_pos.x;
           else if(cur_pos.x < min_x) min_x = cur_pos.x;
           if(cur_pos.y > max_y) max_y = cur_pos.y;
           else if(cur_pos.y < min_y) min_y = cur_pos.y;

      }
       else{ // 방향 전환
           rotate(command.charAt(i));
      }

  }

   int[][] map = new int[max_x - min_x + 1][max_y - min_y + 1];

   // 가장 왼쪽 위 좌표 (0,0)으로 만들기
   for(int i=0; i<poses.size(); i++){
       int x = poses.get(i).x + (-1 * min_x);
       int y = poses.get(i).y + (-1 * min_y);
       map[x][y] = 1;
  }


   // answer
   for(int i=0; i<map.length; i++){
       for(int j=0; j<map[0].length; j++){
           if(map[i][j] == 1)
               System.out.print('.');
           else
               System.out.print("#");
      }
       System.out.println();
  }
}


'알고리즘' 카테고리의 다른 글

[JAVA] 백준 1986 : 체스  (0) 2019.02.21
[JAVA] 백준 1406 : 에디터  (0) 2019.02.16
[JAVA] 백준 2512 : 예산  (0) 2019.02.02
[JAVA] 백준 3985 : 롤케이크  (0) 2019.02.01
[JAVA] 백준 10610 : 30  (0) 2019.02.01

문제

지방의 수 N(3<=N<=10000), 각 지방의 요청 예산, 그리고 전체 예산이 주어졌을 때,

  1. 모든 요청이 배정될 수 있는 경우에는 요청한 금액 그대로 배정한다.

  2. 모든 요청이 배정될 수 없으면 특정한 정수 상한액을 계산하여 배분한다.

위 규칙에 따라 예상을 배정할 때, 가장 크게 산정될 수 있는 상한액을 계산하는 문제



접근방법

  1. 각 지방의 예산region[i] 을 모두 할당할 지, 상한액을 정해야할 지 판단하기 위해서는 ( 남은 지방의 수 * 해당 지방의 예산 ) 이 남은 예산을 초과하는지를 확인하면 된다.

    • 예를 들어 각 지방 요청예산이 [110, 120, 140, 150] 이며, 전체 예산이 485일 때, region[0] 을 볼 때, 나머지 예산들은 모두 110보다는 같거나 크므로, 가장 작아봐야 모두 110이 된다. 이 때, 110*4 는 전체 예산인 485를 넘지 않으므로 110을 모두 할당할 수 있다.

    • 110을 할당한 뒤, 전체 예산은 375가 남고, 그 다음 지방예산인 120을 본다. 남은 지방은 3개가 남았고 모두 가장 작아도 120이므로, 120 * 3을 하면 역시 남은 예산인 375보다 작으므로 해당 지방에도 예산을 모두 배정할 수 있다.

    • 다음 3번째 지방을 보면, 남은 예산은 255가 남았으며 지방은 2개가 남았다. 140 * 2를 하면 남은 예산을 초과하게 되므로 예산을 모두 할당해 줄 수 없고 상한선을 설정해야 한다.

    • 상한선은 남은 예산을 최대한 많이 사용하는 값으로 정해야 하므로, 몇 개의 지방에 배정해주고 남은 예산을 남은 지방에 동일하게 나누어주고 나머지를 버리면 최대 상한값을 얻을 수 있다.


  1. 모든 예산을 배정해줄 수 있을 때의 상한값은 가장 큰 지방 요청 예산이 된다.

    • 배열을 정렬하면 상한값은 region[N-1]이 된다.



소스코드

Scanner sc = new Scanner(System.in);

int N = sc.nextInt();
int[] region = new int[N];
for(int i=0; i<N; i++)
    region[i] = sc.nextInt();

Arrays.sort(region);

int budget = sc.nextInt();
int limit = 0;
for(int i=0; i<N; i++){
    if(region[i] * (N-i) < budget){
        budget -= region[i];
    }else{
        limit = budget/(N-i);
        break;
    }
}

// 모두 예산을 배정할 수 있는 경우
if(limit == 0)
    limit = region[N-1];

System.out.println(limit);


'알고리즘' 카테고리의 다른 글

[JAVA] 백준 1406 : 에디터  (0) 2019.02.16
[JAVA] 백준 1347 : 미로만들기  (0) 2019.02.06
[JAVA] 백준 3985 : 롤케이크  (0) 2019.02.01
[JAVA] 백준 10610 : 30  (0) 2019.02.01
[JAVA] 백준 2980 : 도로와 신호등  (0) 2019.01.21

문제

롤케이크를 L개로 잘랐고, N명의 사람들이 원하는 케이크 조각 번호를 적어 내면 순서대로 조각을 차지하게 된다. 이미 차지한 케이크는 갖지 못하고 그 조각을 제외한 부분만 받게 된다.



접근방법

  1. 처음 사람들이 기대했던 케이크 양을 저장하고, 순서대로 케이크를 차지하게 한 다음, 실제 케이크를 차지한 결과를 확인한다.

  2. 각각의 조각을 먹은 사람들의 인덱스가 저장되어 있는 케이크 배열 cake[], 처음 기대했던 케이크의 양을 가지고 있는 배열 people_before[], 실제로 차지한 케이크 양을 저장하는 people_after[] 배열 사용한다.

  3. 각 케이크에 초기값 0이 아닌 수가 있으면 먹을 수 없으므로, 0일 때에만 값을 바꿔준다.

  4. 최대 케이크 양이 아니라, 케이크를 차지한 사람을 알아야 하므로, max 값과 index 값을 함께 저장하며 for문을 돈다.



소스코드

public static void main(String[] args) throws IOException{

       Scanner sc = new Scanner(System.in);
       int L = sc.nextInt();
       int N = sc.nextInt();
       int[] cake = new int[L+1];           // 케이크 차지 현황
       int[] people_before = new int[N+1];  // 처음 기대했던 케이크 양
       int[] people_after = new int[N+1];   // 실제로 받은 케이크 양

       for(int i=1; i<=N; i++){
           int start = sc.nextInt();
           int end = sc.nextInt();
           // 기대하는 케이크 양 저장
           people_before[i] = end - start + 1;

           // 케이크 차지
           for(int j=start; j<=end; j++)
               if(cake[j] == 0)
                   cake[j] = i;
      }

       // 실제 받은 케이크 양 저장
       for(int i=1; i<=L; i++){
           if(cake[i] != 0)
               ++people_after[cake[i]];
      }

       // 기대, 실제 각각의 max 인덱스 계산
       int max_before = 0, index_before = 0;
       int max_after = 0, index_after = 0;
       for(int i=1; i<=N; i++){
           if(people_before[i] > max_before) {
               max_before = people_before[i];
               index_before = i;
          }
           if(people_after[i] > max_after) {
               max_after = people_after[i];
               index_after = i;
          }
      }

       System.out.println(index_before);
       System.out.println(index_after);

  }


'알고리즘' 카테고리의 다른 글

[JAVA] 백준 1347 : 미로만들기  (0) 2019.02.06
[JAVA] 백준 2512 : 예산  (0) 2019.02.02
[JAVA] 백준 10610 : 30  (0) 2019.02.01
[JAVA] 백준 2980 : 도로와 신호등  (0) 2019.01.21
[JAVA] 백준 2593 : 영역 구하기  (0) 2019.01.20

문제

양수 N(최대 105개의의 숫자)가 있을 때 그 수의 조합을 섞어 가장 큰 30의 배수를 만들어 출력하는 문제. 30의 배수가 만들어지지 않으면 -1을 출력한다.



접근방법

  1. 3의 배수는 각 자리수의 합이 3의 배수이며, 10의 배수는 끝이 0으로 끝나는 것을 이용한다.

    • 즉, 각 자리수를 더한 합이 3의 배수이며 0이 포함되어있으면 30의 배수를 만들 수 있는 수이다.

    • 위의 식이 성립하지 않으면 -1을 출력한다.

  2. 배열을 정렬한 뒤 가장 뒤에서부터 출력하면 가장 큰 30의 배수를 출력할 수 있다.



소스코드

public static void main(String[] args) throws IOException{

       Scanner sc = new Scanner(System.in);
       String input = sc.next();

       int[] N = new int[input.length()];
       int sum = 0;    // 숫자들의 합
       boolean isZero = false; // 0존재 여부
       
       for(int i=0; i<input.length(); i++){
           N[i] = Integer.parseInt(input.charAt(i)+"");
           sum += N[i];
           if(N[i] == 0)
               isZero = true;
      }

       Arrays.sort(N);
       if(sum%3 == 0 && isZero){
           for(int i=N.length-1; i>=0; i--)
               System.out.print(N[i]);
      }else{
           System.out.print(-1);
      }

  }


문제

신호등의 개수(N), 도로의 길이(L)가 주어져 있으며 각 신호등의 도로 위의 위치와 빨간불, 초록불이 유지되는 시간이 주어져 있다. 트럭이 1초에 1m씩 이동하고, 신호를 지켜 도로(Lm)를 다 지나갈 때 몇 초가 걸리는지 계산하는 문제.



접근방법

  1. 신호등 데이터를 도로 배열에 저장한다.

    • Traffic_light라는 클래스를 새로 만들고, 여기에는 빨간불 유지 시간(R), 초록불 유지시간(G)를 가지고 있다.

    • Traffic_light를 타입으로 하는 배열을 선언하고, 신호등의 위치(D)에 신호등 데이터(R, G)를 저장한다. load[D] = new Traffic_light(R, G)

  1. 일정한 규칙으로 반복되는 신호등이 x초일 때 얼마나 기다려야 하는지를 계산한다.

    • 나머지 연산을 이용해 계산한다.

    • 예를 들어 (4, 2)로 반복되는 신호등은 xxxxoo가 반복되는데 time=7인 경우에는 7%6로 해서 첫번째 x에 해당된다.

    • 남은 시간을 계산할 때에는 전체 R에서 7%6인 1을 뺀 값을 더해준다. 즉, 3초를 기다리므로 3을 더해준다.



소스코드

static class Traffic_light{
   int R; int G;
   public Traffic_light(int r, int g) {this.R = r; this.G = g;}
}

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

   String[] input = in.readLine().split(" ");
   int N = Integer.parseInt(input[0]);
   int L = Integer.parseInt(input[1]);

   // 도로 위 신호등 확인 배열
   Traffic_light[] load = new Traffic_light[L+1];

   for(int i=0; i<N; i++){
       String[] input_data = in.readLine().split(" ");
       int D = Integer.parseInt(input_data[0]);
       int R = Integer.parseInt(input_data[1]);
       int G = Integer.parseInt(input_data[2]);

       load[D] = new Traffic_light(R, G);
  }

   int time = 0;
   int pos = 0;
   while(pos < L){

       ++time; //시간초 증가
       ++pos;  // 다음 위치로 이동

       // 다음에 이동할 곳에 신호등이 있는 경우
       if(load[pos] != null){

           int check = time % (load[pos].R + load[pos].G);

           // 현재 빨간불인 경우 기다렸다가 지나감
           if(check <= load[pos].R){
               time += (load[pos].R - check);
          }
      }
  }

   System.out.println(time);

}


'알고리즘' 카테고리의 다른 글

[JAVA] 백준 3985 : 롤케이크  (0) 2019.02.01
[JAVA] 백준 10610 : 30  (0) 2019.02.01
[JAVA] 백준 2593 : 영역 구하기  (0) 2019.01.20
[JAVA] 백준 1018 : 체스판 다시 칠하기  (0) 2019.01.16
[JAVA] 백준 1120 : 문자열  (0) 2019.01.13

+ Recent posts