1. CMAK를 설치하게 된 이유

Kafka Manager는 GUI 기반 카프카 관리도구이다.

배치를 돌리면서 consumer하는 속도보다 producer 하는 속도가 더 빨라 설정된 kafka 메모리 초과로 배치가 제대로 실행되지 않았던 경험이있어, 카프카 모니터링 툴을 찾던 중 오픈소스인 CMAK를 설치하기로 했다.

 

카프카 모니터링 툴은 CMAK외에도 Kafdrop, Burrow 등 여러 오픈소스가 존재하지만,

설치가 간단하고, GUI로 토픽을 생성 및 변경할 수 있으면 좋을 것 같아 CMAK를 선택했다.

 

CMAK의 주요 기능

CMAK에서 제공하는 기능은 다음과 같다.

1. Kafka Cluster 관리

2. Consumer Lag 관리

3. GUI로 토픽 생성 및 변경

4. 파티션 추가

 

 

2. CMAK 설치

설치할 서버환경

  • CentOS 7

CMAK 설치 전, 기본 환경

  • JDK 11 이상
  • kafka 0.8 이상

 

1) tar.gz 파일 다운로드

# wget https://github.com/yahoo/CMAK/archive/refs/tags/3.0.0.6.tar.gz
# tar -zxvf 3.0.0.6.tar..gz

 

2) 현재 서버는 jdk1.8이지만 CMAK는 최소 JDK11 이상이기 때문에 sbt 파일을 수정했다.

- 1)에서 압축을 푼 파일로 이동하면 sbt 파일이 있다.

# vi sbt


[sbt]
-- 35번째 java_cmd 경로를 설치한 jdk11 위치로 변경

declare sbt_jar sbt_dir sbt_create sbt_version sbt_script sbt_new
declare sbt_explicit_version
declare verbose noshare batch trace_level

# declare java_cmd="java"
declare java_cmd="/usr/lib/jvm/jdk-11/bin/java" --이렇게!
declare sbt_launch_dir="$HOME/.sbt/launchers"
declare sbt_launch_repo

 

 

3) 빌드

# ./sbt clean dist

- 설치경로/CMAK-3.0.0.6/target/universal/cmak-3.0.0.6 생성된걸 확인 할 수 있다.

 

4) cofing 파일 수정

# cd /빌드한 파일 경로/confi/

-- application.conf 파일 수정

# Settings prefixed with 'kafka-manager.' will be deprecated, use 'cmak.' instead.
# https://github.com/yahoo/CMAK/issues/713
# kafka-manager.zkhosts="kafka-manager-zookeeper:2181"
kafka-manager.zkhosts="localhost:2181"
kafka-manager.zkhosts=${?ZK_HOSTS}
# cmak.zkhosts="kafka-manager-zookeeper:2181"
cmak.zkhosts="localhost:2181"
cmak.zkhosts=${?ZK_HOSTS}

 

5) 실행

# cd /app/kafkaManager/CMAK-3.0.0.6/target/univeral/cmak-3.0.0.6
# bin/cmak -Dhttp.port=9003 -java-home /usr/lib/jvm/jdk-11

- 자바버전을 11으로 잡아주기 위해 JAVA_HOME을 따로 잡아주었다.

- 기본 포트는 9000번이지만, 옵션을 통해 9003으로 변경해주었다. 

 

 

3. 실행결과 확인

 

 

1417번: 국회의원 선거

첫째 줄에 후보의 수 N이 주어진다. 둘째 줄부터 차례대로 기호 1번을 찍으려고 하는 사람의 수, 기호 2번을 찍으려고 하는 수, 이렇게 총 N개의 줄에 걸쳐 입력이 들어온다. N은 50보다 작거나 같

www.acmicpc.net

 

# 풀이 방법

국회의원 후보들 중 다솜이가 당선되어야 하기 때문에

현재 가장 많은 투표수를 가지고 있는 후보의 표를 다솜이에게 주면서 표수를 확인하는 방식으로 문제를 풀었습니다.

 

후보 수와 그 후보의 득표 수를 저장할 info 객체를 하나 만들어 다솜이를 제외한 후보의 정보를 우선순위 큐에 넣어주었습니다.

 

while문을 돌면서 우선순위 큐가 비었거나, 다솜이를 제외한 후보들 중 가장 많은 득표수를 가지고 있는 후보와 다솜이의 득표수를 비교해 다솜이가 더 많다면 더 이상 매수할 필요가 없으니 반복문을 종료했습니다.

반대로 다솜이보다 득표수가 많다면 그 후보의 표를 다솜이에게 주기 위해 -1 / +1을 하면서 다솜이의 득표수가 가장 많아질 때까지 반복해 주었습니다.

 

# 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.PriorityQueue;
 
public class Main_BJ_1417_국회의원선거 {
    
    static class Info{
        int number, vote;
 
        public Info(int number, int vote) {
            this.number = number;
            this.vote = vote;
        }
    }
    
    static int N;
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PriorityQueue<Info> pq = new PriorityQueue<>(new Comparator<Info>() {
 
            @Override
            public int compare(Info o1, Info o2) {
                return (o1.vote-o2.vote)*-1;
            }
        });
        
        N = Integer.parseInt(br.readLine());
        
        Info dasom = new Info(1, Integer.parseInt(br.readLine()));
        for(int i=2;i<=N;i++) {
            pq.add(new Info(i, Integer.parseInt(br.readLine())));
        }
        
        int count=0;
        while(true) {
            if(pq.isEmpty()||dasom.vote>pq.peek().vote) break;
            
            Info temp = pq.poll();
            dasom.vote=dasom.vote+1;
            pq.add(new Info(temp.number, temp.vote-1));
            count++;
        }
        
        System.out.println(count);
 
    }
 
}
cs

 

'문제 > 백준' 카테고리의 다른 글

백준 1918번 후위 표기식 [JAVA]  (0) 2022.04.26
백준 21608 상어 초등학교 [JAVA]  (0) 2021.12.01
백준 17143번 낚시왕 [JAVA]  (0) 2021.12.01
백준 13549번 숨바꼭질3 [JAVA]  (0) 2021.11.23
백준 3085번 사탕 게임 [JAVA]  (0) 2021.11.18

제45회 SQLD 시험 후기

2022년 05월 28일 (토)에 시행된 제45회 SQLD 시험을 보고 왔다.

사실 44회 시험을 보려고 했는데 접수일자를 놓쳐서 45회를 봤다ㅎㅎ

코테에서도 SQL문제가 나오는 경우가 있는데, 코테 대비 겸 SQL기본기를 잡아보고자 자격증을 따기로 마음먹었다.

 

1. 공부기간

공부기간은 대략 7~10일 정도로 짧았고,

평일에는 퇴근 후 SQLD 이론 요약된 PDF를 가볍게 읽었다.

시험 일주일 전부터는 요약본 + 노랭이(SQL 자격검정 실전문제)를 풀었으며, 틀린 문제는 오답노트를 작성해 문제에 대한 개념과 오답인 이유를 정리했다.

시험 2일 전부터는 SQLD 복원된 기출문제를 풀면서 부족한 부분을 채워나갔다.

노랭이 풀면서 개념 정리 및 오답

 

2. 시험후기

사실 노랭이 풀면서 은근히 헷갈리는 것도 많고, 모르는 것도 있어서 걱정했는데 노랭이보다는 쉽게 나오는 것 같다.

시험 전날에 노랭이 + 기출문제 틀린 부분을 위주로 정리했는데

당일 시험에서 비슷한 문제/똑같은 문제가 꽤 보여서 놀랬다.

SQLD 시험 준비하면서 나름 개념들을 정리할 수 있는 시간이었던 것 같다!

 

# 22.06.19 추가

22.06.17 (금)에 시험 사전점수가 공개되었다는 문자를 받았다.

데이터 자격검정 페이지에 들어가 보니 시험 점수와 함께 합격 예정을 확인할 수 있었다!

자격증은 결과발표일(22.06.24) 10시 이후부터 출력할 수 있다고 한다.

 

 

3. 참고

 

데이터 전문가 포럼 (빅데이터분석기사... : 네이버 카페

빅데이터분석기사, ADP, ADsP, SQLP, SQLD, DAP, DAsP, 자격증 취득 등 데이터 전문가 커뮤니티입니다.

cafe.naver.com

SQLD, SQLP 등 데이터 관련 자료가 많이 공유되어있어 자격증 공부하는데 많은 도움이 되었다.

또한 노랭이를 풀다가 이해가 안 되는 부분은 이 카페를 참고했다.

카페에 복원된 기출문제도 있어서 풀어보면 많은 도움이 될 것 같다.

 

1918번: 후위 표기식

첫째 줄에 중위 표기식이 주어진다. 단 이 수식의 피연산자는 알파벳 대문자로 이루어지며 수식에서 한 번씩만 등장한다. 그리고 -A+B와 같이 -가 가장 앞에 오거나 AB와 같이 *가 생략되는 등의

www.acmicpc.net

 

풀이 방법

연산자에 우선순위를 부여하여 HashMap에 저장해 연산자 비교를 쉽게 할 수 있도록 했습니다.

 

만약 숫자라면 출력하고,

연산자라면 스택에 있는 연산자와 비교하여 우선순위를 이용해 스택에 저장할지 아님 출력할지를 결정했습니다.

 

또한 ')'인 경우에는 반복문을 돌면서 '('가 나올 때까지 출력했습니다.

그리고 for문이 끝난 뒤에는 stack에 저장된 값이 있다면 stack이 빌 때까지 출력해주었습니다.

 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Stack;
 
public class Main_BJ_1918_후위표기식 {
    
    static HashMap<Character, Integer> hm = new HashMap<>(); 
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        StringBuilder sb = new StringBuilder();
        
        Stack<Character> stack = new Stack<>();
        
        hm.put('*'3); hm.put('/'3);
        hm.put('+'2); hm.put('-'2);
        hm.put('('1); hm.put(')'1);
        
        String line = br.readLine();
        for(int i=0;i<line.length();i++) {
            char c = line.charAt(i);
            if(c=='(') stack.push(c);
            else if(c>=65 && c<=90) sb.append(c);
            else if(c=='+' || c=='-' || c=='*' || c=='/') {
                while(!stack.isEmpty()) {
                    if(priority(c)<=priority(stack.peek())) {
                        sb.append(stack.pop());
                    }else break;
                }
                stack.push(c);
            }else if(c==')') {
                while(!stack.isEmpty()) {
                    char top = stack.pop();
                    if(top=='('break;
                    else sb.append(top);
                }
            }
        }
        
        while(!stack.isEmpty()) sb.append(stack.pop());
        
        System.out.println(sb.toString());
    }

    public static int priority(char key) {
        return hm.get(key);
    }
 
}
 
cs

 

이펙티브 자바를 공부하면서 플라이웨이트 패턴이 나와 개념 정리 및 실습을 해보려고 한다.

 

1. 플라이웨이트 패턴(Flyweight Pattern)이란?


동일하거나 유사한 객체들 사이에 가능한 많은 데이터를 서로 공유하여 사용하도록 하여 메모리 사용량을 최소화하는 디자인 패턴이다.

즉, 자주 변하는 속성과 변하지 않는 속성을 분리하고, 변하지 않는 속성은 재사용하여 메모리 사용을 줄이는 방식이다.

 

 

2. Flyweight Pattern의 구성


  • Flyweight : 공유에 사용할 클래스
  • FlyweightFactory : Flyweight 인스턴스를 생성 또는 공유
  • Client : Flyweight : 해당 패턴의 사용자

 

3. 실습


  • Shape (공유에 사용할 클래스들의 인터페이스)
public interface Shape {
	public void draw();
}

 

  • Circle (인터페이스 내용 및 필요한 속성 정의)
public class Circle implements Shape {
	
	private String color;
	private int x;
	private int y;
	private int radius;
	
	public Circle(String color) {
		this.color = color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public void setX(int x) {
		this.x = x;
	}


	public void setY(int y) {
		this.y = y;
	}

	public void setRadius(int radius) {
		this.radius = radius;
	}

	@Override
	public void draw() {
		System.out.println("Circle [color= " + color +" , x= "+ x + " , y= "+ y +" , radius= "+ radius + " ]" );
	}
}

 

  • ShapeFactory (객체의 생성 또는 공유의 역할)
import java.util.HashMap;

public class ShapeFactory {
	public static final HashMap<String, Circle> circleMap = new HashMap<>();
	
	public static Shape getCircle(String color) {
		Circle circle = circleMap.get(color);
		
		if(circle == null) {
			circle = new Circle(color);
			circleMap.put(color, circle);
			System.out.println("---- 새로운 객체 생성 " + color +"색 원 ----" );
		}
		return circle;
	}
}

 

  • Main 클래스
public class Main {

	public static void main(String[] args) {
		String[] colors = {"Red", "Yellow", "Pink", "Blue"};
		
		for(int i=0;i<10;i++) {
			Circle circle = (Circle) ShapeFactory.getCircle(colors[(int) (Math.random()*4)]);
			circle.setX((int) (Math.random()*10));
			circle.setY((int) (Math.random()*20));
			circle.setRadius((int) (Math.random()*10));
			circle.draw();
		}
	}
}

 

  • 실행결과
---- 새로운 객체 생성 Blue색  ----
Circle [color= Blue , x= 8 , y= 5 , radius= 0 ]
---- 새로운 객체 생성 Red색  ----
Circle [color= Red , x= 5 , y= 5 , radius= 5 ]
---- 새로운 객체 생성 Pink색  ----
Circle [color= Pink , x= 6 , y= 17 , radius= 4 ]
Circle [color= Blue , x= 0 , y= 1 , radius= 6 ]
---- 새로운 객체 생성 Yellow색  ----
Circle [color= Yellow , x= 7 , y= 1 , radius= 4 ]
Circle [color= Yellow , x= 1 , y= 2 , radius= 0 ]
Circle [color= Red , x= 0 , y= 13 , radius= 3 ]
Circle [color= Yellow , x= 9 , y= 5 , radius= 1 ]
Circle [color= Pink , x= 1 , y= 16 , radius= 0 ]
Circle [color= Red , x= 7 , y= 11 , radius= 2 ]

같은 색상의 원은 1개만 생성되며, 생성된 객체를 공유하는 것을 확인할 수 있다.

 

 

4. 결론


4.1 언제 플라이웨이트 패턴을 사용하면 좋을까?

  • 공통적인 인스턴스를 많이 생성하는 로직이 포함된 경우
  • 자주 변하지 않는 속성을 재사용하는 경우

 

4.2 싱클톤 패턴과의 차이는 뭘까?

  • 싱클톤 패턴은 클래스 자체가 오직 1개의 인스턴스만 허용
  • 플라이웨이트 패턴은 싱글톤이 아닌 클래스 팩토리에서 제어

--> 인스턴스 생성의 제한을 어디서 제어하느냐의 차이

 

4.3 어디에서 플라이웨이트 패턴을 사용할까?

  • 임베디드와 같이 메모리를 최소한으로 사용해야 하는 경우에 활용
  • 클래스의 객체를 많이 만들어야할 때 사용

 

 

 

## 참고한 블로그 ##

 

[디자인패턴/Design Pattern] Flyweight Pattern / 플라이웨이트 패턴

관련 내용은 [자바 언어로 배우는 디자인 패턴 입문] , [Head First Design Pattern] 의 내용을 참고해서 정리한 글입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다. 1. Flyweight 패턴이란? 어떤 클래스

lee1535.tistory.com

 

[구조 패턴] 플라이웨이트 패턴

1. 플라이웨이트 패턴(Flyweight Pattern)이란? 객체를 가볍게 만들어 메모리 사용을 줄이는 패턴 공통으로 사용하는 클래스(Flyweight)를 생성하는 팩토리 클래스(FlyweightFactory)를 만들어, 인스턴스를 최

dev-youngjun.tistory.com

 

'정리 > Design Pattern' 카테고리의 다른 글

Visitor Pattern - 방문자 패턴  (0) 2022.01.04
 
 

1. Visitor Pattern 이란?
2. Visitor Pattern의 적용 예시

 

1️⃣ Visitor Pattern

  • 방문자와 방문 공간을 분리하여, 방문 공간이 방문자를 맞이할 때, 이후에 대한 행동을 방문자에게 위임하는 패턴
  • 알고리즘을 객체 구조에서 분리시키는 디자인 패턴
    ⇒ 개방-폐쇄 원칙을 적용하는 방법 중 하나
    ⇒ 구조를 수정하지 않고도 실질적으로 새로운 동작을 기존의 객체 구조에 추가할 수 있게 된다.

 

예시

  • 쇼핑몰 고객을 등급별로 나누고 등급에 따라 혜택을 주기로 한다.
  • 등급은 Gold, Vip가 있고 혜택은 포인트, 할인이 있다.
  • 고객 등급별 혜택을 줄 수 있는 확장 가능한 해결책을 찾아보자.

 

public interface Member { }

public class GoldMember implements Member { }

public class VipMember implements Member { }

  • Member 인터페이스를 사용해서 등급별로 구체 클래스 생성

 

public class GoldMember implements Member {
	public void point() { System.out.println("Point for Gold Member"); }
	public void discount() { System.out.println("Discount for Gold Member"); }
}

public class VipMember implements Member {
	public void point() { System.out.println("Point for Vip Member"); }
	public void discount() { System.out.println("Discount for Vip Member"); }
}
  • 등급별 혜택 구현

 

public class Main {
	public static void main(String[] args) {
		Member gold = new GoldMember();
		Member vip = new VipMember();

		gold.point();
		vip.point();
		gold.discount();
		vip.discount();
	}
}
//실행 결과
Point for Gold Member
Point for Vip Member
Discount for Gold Member
Discount for Vip Member

 

 

⭐ 문제점 ⭐

  • 고객들에게 혜택을 주고자 할 때 명시적으로 혜택을 주기 위한 메소드를 호출해야한다.
  • 혜택이 늘어났을 경우 모든 멤버들에 대해 그 혜택을 구현했다는 보장이 없다.

 

 

⭐ 해결방안 ⭐

public interface Benefit {
    void getBenefit(GoldMember member);
    void getBenefit(VipMember member);
}
  • Benefit 인터페이스에 혜택을 받을 Member 별로 실행 가능한 메소드 정의

 

public class DiscountBenefit implements Benefit {
    @Override
    public void getBenefit(GoldMember member) {
        System.out.println("Discount for Gold Member");
    }

    @Override
    public void getBenefit(VipMember member) {
        System.out.println("Discount for Vip Member");
    }
}

public class PointBenefit implements Benefit {
    @Override
    public void getBenefit(GoldMember member) {
        System.out.println("Point for Gold Member");
    }

    @Override
    public void getBenefit(VipMember member) {
        System.out.println("Point for Vip Member");
    }
}
  • 멤버 등급별 혜택에 대해 기능 구현

 

public interface Member {
    void getBenefit(Benefit benefit);
}
  • 등급별 멤버가 혜택을 받을 수 있는 메소드를 Member 인터페이스에 선언

 

public class GoldMember implements Member {
    @Override
    public void getBenefit(Benefit benefit) {
        benefit.getBenefit(this);
    }
}

public class VipMember implements Member {
    @Override
    public void getBenefit(Benefit benefit) {
        benefit.getBenefit(this);
    }
}
  • 혜택받는 메소드 구현
  • 다른 Member가 추가되더라도 구현 부분은 benefit.getBenefit(Benefit benefit); 만 넣으면 된다.

 

public class Main {
    public static void main(String[] args) {
        Member goldMember = new GoldMember();
        Member vipMember = new VipMember();
        Benefit pointBenefit = new PointBenefit();
        Benefit discountBenefit = new DiscountBenefit();

        goldMember.getBenefit(pointBenefit);
        vipMember.getBenefit(pointBenefit);
        goldMember.getBenefit(discountBenefit);
        vipMember.getBenefit(discountBenefit);
    }
}

//실행 결과
Point for Gold Member
Point for Vip Member
Discount for Gold Member
Discount for Vip Member

 

⭐ 결과 ⭐

  • Visitor 패턴에서는 혜택이 늘어나더라도 Benefit 인터페이스에 명시적으로 등급별 메소드를 정의하고 있어 구현 누락이 발생하지 않는다.
  • 혜택을 추가하기 위해서 해당 혜택을 구현하는 클래스를 추가하면 되므로, 코드 중복이 발생하지 않는다.

 

⭐ Visitor 패턴을 언제 쓰면 좋을까? ⭐

  • 대상 객체가 잘 바뀌지 않고, 적용할 알고리즘이 추가될 가능성이 많은 상황일 때

 

 

참고

https://thecodinglog.github.io/design/2019/10/29/visitor-pattern.html

https://velog.io/@cham/Design-Pattern-방문자-패턴-Visitor-pattern

'정리 > Design Pattern' 카테고리의 다른 글

Flyweight Pattern - 플라이웨이트 패턴  (0) 2022.03.31
 

16469번: 소년 점프

첫째 줄에 미로의 행과 열의 크기를 나타내는 자연수 R과 C가 주어진다. (2 ≤ R, C ≤ 100) 다음 R줄에 걸 쳐 길이 C로 이루어진 각 줄의 미로의 정보가 공백 없이 주어진다. 숫자 0은 이동 가능한

www.acmicpc.net

 

풀이 방법

세명의 위치가 주어질 때 한 지점에 세명이 모일 때의 최소가 되는 시간을 구하는 문제였습니다.

 

저는 세명의 정보를 큐에 넣어두고 상 하 좌 우로 움직이면서 방문하지 않은 곳이라면 map배열의 값을 하나 올려주었습니다. 해당 위치의 값이 3일 경우에는 세명 모두 해당 위치를 방문했으므로 time 배열에 해당 시간을 넣어주었습니다. 그리고 find() 메서드에서 가장 최소 시간을 찾고 그러한 지점의 개수를 함께 출력해주었습니다.

 

⭐100%에서 틀렸습니다가 나오신다면.. 반례로

2 2
00
00
1 1
1 2
2 2

넣어보세요! ㅎㅎ ⭐

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.IOException;
 
public class Main {
    
    static class info{
        int x,y,time;
        boolean [][] visited;
        public info(int x, int y, int time, boolean[][] visited) {
            super();
            this.x = x;
            this.y = y;
            this.time = time;
            this.visited = visited;
        }
    }
    
    static int [][] map, time;
    static int [] dx = {-1,0,1,0};
    static int [] dy = {0,1,0,-1};
    
    static int R,C;
    static Queue<info> queue = new LinkedList<>();
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        
        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        
        map = new int[R][C];
        time = new int[R][C];
        
        for(int i=0;i<R;i++) {
            String line = br.readLine();
            for(int j=0;j<C;j++) {
                map[i][j] = line.charAt(j)-48;
                if(map[i][j]==1) map[i][j] = -1;
            }
        }
        
        for(int i=0;i<3;i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken())-1;
            int y = Integer.parseInt(st.nextToken())-1;
            
            queue.add(new info(x,y,0,new boolean[R][C]));
            map[x][y] = 1;
        }
        
        bfs();
        find();
    }
    
    public static void bfs() {
        
        
        while(!queue.isEmpty()) {
            info temp = queue.poll();
            temp.visited[temp.x][temp.y] = true;
            
            for(int i=0;i<4;i++) {
                int nx = temp.x+dx[i];
                int ny = temp.y+dy[i];
                
                if(range(nx,ny) && map[nx][ny]!=-1 && !temp.visited[nx][ny]) {
                    temp.visited[nx][ny] = true;
                    map[nx][ny]++;
                    queue.add(new info(nx,ny,temp.time+1,temp.visited));
                    
                    if(map[nx][ny]==3) time[nx][ny] = temp.time+1;
                }                
            }
        }
    }
    
    public static boolean range(int x ,int y) {
        return x>=0 && x<&& y>=0 && y<C;
    }
    
    public static void find() {
        int min = Integer.MAX_VALUE, count=0;
        for(int i=0;i<R;i++) {
            for(int j=0;j<C;j++) {
                if(time[i][j]!=0 && min>time[i][j]) {
                    min = time[i][j];
                    count=1;
                }
                
                else if(min==time[i][j]) count++;
            }
        }
        
        if(min==Integer.MAX_VALUE) System.out.println("-1");
        else {
            System.out.println(min+"\n"+count);
        }
    }
}
cs

 

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

 

풀이 방법

학생의 자리를 정하는데 다음과 같은 규칙이 존재합니다.

  1. 비어있는 칸 중에서 좋아하는 학생이 인접한 칸에 가장 많은 칸으로 자리를 정한다.
  2. 1을 만족하는 칸이 여러 개이면, 인접한 칸 중에서 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
  3. 2를 만족하는 칸도 여러 개인 경우에는 행의 번호가 가장 작은 칸으로, 그러한 칸도 여러 개이면 열의 번호가 가장 작은 칸으로 자리를 정한다.

해당 학생이 좋아하는 학생의 번호를 저장하기 위해서 배열 안에 List를 넣어주었습니다.

해당 조건에 맞는 학생의 자리를 찾기위해 like와 empty배열을 사용하여 좋아하는 학생이 얼마나 인접해있는지와 비어있는 칸은 몇 개인지를 확인해 배열에 저장해주었습니다. 배열에 저장된 데이터를 기준으로 조건 1,2,3을 충족하는 경우에 해당 학생 자리를 배치해주는 방식으로 구현했습니다.

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
 
public class Main_BJ_21608_상어초등학교 {
    
    static int N, answer=0;
    static int [][] seat, like, empty;
    static List<Integer> list[];
    static List<int []> condition1, condition2;
    
    static int [] dx = {-1,0,1,0};
    static int [] dy = {0,1,0,-1};
    static int [] score = {0,1,10,100,1000};
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        
        N = Integer.parseInt(br.readLine());
        
        seat = new int[N][N];
        
        list = new ArrayList[N*N+1];
        
        for(int i=1;i<N*N+1;i++) list[i] = new ArrayList<>();
        
        for(int i=0;i<N*N;i++) {
            st = new StringTokenizer(br.readLine());
            int student = Integer.parseInt(st.nextToken());
            for(int j=0;j<4;j++) {
                list[student].add(Integer.parseInt(st.nextToken()));
            }
            findSeat(student);
        }
        
        cal();
        System.out.println(answer);
 
    }
    
    
    public static void findSeat(int student) {
        like = new int[N][N];
        empty = new int[N][N];
        condition1 = new ArrayList<>();
        condition2 = new ArrayList<>();
        
        for(int i=0;i<N;i++) {
            for(int j=0;j<N;j++) {
                if(seat[i][j]==0) {
                    for(int d=0;d<4;d++) {
                        int nx = i+dx[d];
                        int ny = j+dy[d];
                        if(range(nx,ny)) {
                            if(list[student].contains(seat[nx][ny])) { //인접한 좋아하는 학생
                                like[i][j]++;
                            }
                            else if(seat[nx][ny]==0) { //인접한 빈 곳
                                empty[i][j]++;
                            }
                        }
                    }
                }
            }
        }
        
        int max=0;
        for(int i=0;i<N;i++) {
            for(int j=0;j<N;j++) {
                if(seat[i][j]==0) {
                    if(max<like[i][j]) {
                        max = like[i][j];
                        condition1.clear();
                        condition1.add(new int[] {i,j});
                    }else if(max==like[i][j]) {
                        condition1.add(new int[] {i,j});
                    }
                }
            }
        }
       //condition1 리스트 사이즈가 1인경우 조건1충족
        if(condition1.size()==1) seat[condition1.get(0)[0]][condition1.get(0)[1]] = student;
        else { //아닌 경우 조건 2,3고려
            max =0;
            for(int i=0;i<condition1.size();i++) {
                int [] temp = condition1.get(i);
                
                if(max<empty[temp[0]][temp[1]]) {
                    max = empty[temp[0]][temp[1]];
                    condition2.clear();
                    condition2.add(new int[] {temp[0],temp[1]});
                }else if(max==empty[temp[0]][temp[1]]) {
                    condition2.add(new int[] {temp[0],temp[1]});
                }
            }
            seat[condition2.get(0)[0]][condition2.get(0)[1]]= student;    
        }
        
    }
    
    public static boolean range(int x, int y) {
        return x>=0 && x<&& y>=0 && y<N;
    }
 
    public static void cal() {
        int count=0;
        for(int i=0;i<N;i++) {
            for(int j=0;j<N;j++) {
                count=0;
                for(int d=0;d<4;d++) {
                    int nx = i+dx[d];
                    int ny = j+dy[d];
                    
                    if(range(nx,ny) && list[seat[i][j]].contains(seat[nx][ny])) count++;
                }
                answer+=score[count];
            }
        }
    }
}
cs

 

 

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.

www.acmicpc.net

 

풀이 방법

이 낚시왕 문제는 다시 풀어본 문제라 확실히 전보다는 코드가 더 깔끔해진 것 같습니다!

 

먼저,

1. 사람을 오른쪽으로 한 칸 움직인 뒤, 땅과 가장 가까운 상어를 하나 잡기

2. 격자판에 있는 상어를 움직이기

로 풀면 되는 시뮬레이션 문제였습니다.

 

저는 객체 배열을 하나 생성해 해당 위치에 상어의 정보를 넣어주었습니다. 상어가 움직일 때는 새로운 배열에 저장해 놓고 다 움직이고 난 뒤, 원래 배열에 복사해 넣는 방식으로 구현했습니다.

(상어 움직이는 것을 for문이 아닌 mod로 한다면 더 빨라질 것 같습니다!)

 

 

<예전 풀이>

 

백준 17143번 낚시왕 [JAVA]

문제 낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸

javaju.tistory.com

 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_BJ_17143_낚시왕 {
    
    static class shark {
        int s,d,z;
 
        public shark(int s, int d, int z) {
            super();
            this.s = s;
            this.d = d;
            this.z = z;
        }
        
    }
    
    static int R,C,M, answer=0;
    static shark [][] map, copy;
    static int [] dx = {0,-1,1,0,0};
    static int [] dy = {0,0,0,1,-1};
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        
        R = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken()); //상어 수
        
        map = new shark[R][C];
        
        for(int i=0;i<M;i++) {
            st = new StringTokenizer(br.readLine());
            
            int r = Integer.parseInt(st.nextToken())-1
            int c = Integer.parseInt(st.nextToken())-1;
            int s = Integer.parseInt(st.nextToken()); //속력
            int d = Integer.parseInt(st.nextToken()); //이동 방향
            int z = Integer.parseInt(st.nextToken()); //크기
            
            map[r][c] = new shark(s,d,z);
        }
        
        for(int i=0;i<C;i++) {
            //1.한칸 이동해서 땅과 가장 가까운 상어 잡아먹기
            movePerson(i);
            
            //2.상어 이동하기
            moveShark();
        }
        
        System.out.println(answer);
    }
    
    public static void movePerson(int y) {
        for(int i=0;i<R;i++) {
            if(map[i][y]!=null) {
                answer+=map[i][y].z;
                map[i][y]=null;
                return;
            }
        }
    }
    
    public static void moveShark() {
        copy = new shark[R][C];
        
        for(int i=0;i<R;i++) {
            for(int j=0;j<C;j++) {
                if(map[i][j]!=null) { //상어 움직이자!
                    shark temp = map[i][j];
                    map[i][j] = null;
                    
                    int nx=i,ny=j;
                    for(int k=0;k<temp.s;k++) {
                        if(temp.d==1 && nx==0) temp.d=2;
                        else if(temp.d==2 && nx==R-1) temp.d=1;
                        else if(temp.d==3 && ny==C-1) temp.d=4;
                        else if(temp.d==4 && ny==0) temp.d=3;
                        
                        nx+=dx[temp.d];
                        ny+=dy[temp.d];
                    }
                    
                    if(copy[nx][ny]==null || copy[nx][ny].z<temp.z ) {
                        copy[nx][ny] = temp;
                    }
                }
            }
        }
        map = copy;
    }
}
cs

 

 

 

13549번: 숨바꼭질 3

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

 

풀이 방법

N의 위치에서 K위치까지 가는데 걸리는 최소의 시간을 구하는 문제였습니다.

 

저는 BFS알고리즘을 사용하여 문제를 풀었으며,

for문을 이용해 순간 이동할 때와 걸을 경우를 구분하여 우선순위 큐에 넣어주었습니다. 방문을 확인하는 visited배열을 이용하여 해당 이동한 곳이 방문한 곳이 아닐 경우에만 이동할 수 있도록 구현했습니다. 우선순위 큐로 움직인 횟수가 가장 작은 것부터 움직일 수 있도록 했기 때문에 만약 현재 위치가 동생이 있는 곳이라면 시간을 출력해주고 반복문을 종료해주었습니다. 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
 
public class Main_BJ_13549_숨바꼭질3 {
    
    static class info implements Comparable<info>{
        int position, time;
 
        public info(int position, int time) {
            super();
            this.position = position;
            this.time = time;
        }
 
        @Override
        public int compareTo(info o) {
            return this.time-o.time;
        }
    }
    
    static int N,K;
    static boolean [] visited;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
 
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
 
        visited = new boolean[100001];
        
        move();
    }
    
    public static void move() {
        Queue<info> pq = new LinkedList<>();
        
        pq.add(new info(N,0));
        
        while(!pq.isEmpty()) {
            info temp = pq.poll();
            
            if(temp.position == K) {
                System.out.println(temp.time);
                return;
            }
            
            int nx = 0;
            for(int i=0;i<3;i++) {
                if(i==0) nx = temp.position*2;
                else if(i==1) nx = temp.position-1;
                else if(i==2) nx = temp.position+1;
                
                if(range(nx) && !visited[nx]) {
                    if(i==1 || i==2) pq.add(new info(nx, temp.time+1));
                    else pq.add(new info(nx, temp.time));
                    visited[nx] = true;
                }
            }
        }
    }
    
    public static boolean range(int x) {
        return x>=0 && x<visited.length;
    }
 
}
cs

 

 

+ Recent posts