반응형
12-13 04:59
Today
Total
«   2024/12   »
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
관리 메뉴

개발하는 고라니

[백준] 10473번 : 인간 대포 본문

Programming/백준

[백준] 10473번 : 인간 대포

조용한고라니 2021. 3. 19. 22:45
반응형
 

10473번: 인간 대포

입력은 한 개의 길찾기 문제를 표현한다. 첫 줄에는 두 개의 실수가 입력되며 각각은 당신이 현재 위치한 X, Y좌표이다. 두 번째 줄에는 목적지의 X, Y좌표가 실수로 입력된다. 이어지는 줄에는 대

www.acmicpc.net


[Dijkstra]

이 문제의 정점은 n+2개다. 출발점, 도착점, 그리고 n개의 대포들. 다음과 같은 주의사항을 지닌다.

 

1) 출발점/도착점은 인간 대포를 사용할 수 없다.

2) 한 정점에서 다른 정점으로 갈 수 있는 방법은 오직 걸음으로만 가거나, (인간 대포 + 걸음)을 이용하는 방법이 있다. (단, 출발점/도착점은 제외)

3) 대포를 사용할 시, 거리가 50 이상일 때와, 50 미만일 때를 고려해야한다.

 

나는 정점에 대한 클래스와 간선에 대한 클래스를 정의하였다. 정점 클래스는 해당 정점의 (y, x)와 몇 번째 정점인지를 갖는다. 출발점은 0번 정점이고, 도착점은 n+1번 정점이다.

    static class Vertex{
        float y, x;
        int idx;

        public Vertex(float y, float x, int idx){
            this.y=y;
            this.x=x;
            this.idx=idx;
        }
    }

 

간선에 대한 클래스는 타겟 정점이 몇번인지, 그 정점까지의 거리 및 현재까지 걸린 시간을 갖는다.

    static class Edge{
        int target;
        float dist, sec;

        public Edge(int tg, float d, float sec){
            target = tg;
            dist = d;
            this.sec = sec;
        }
    }

거리를 구하는 공식은 점과 점 사이의 거리 구하기 공식을 사용했다.

    static float getDist(Vertex a, Vertex b){

        return (float) Math.sqrt( Math.pow(a.y - b.y, 2) + Math.pow(a.x - b.x, 2) );
    }

 

다음은 다익스트라 메서드의 일부이다.

            for(Edge ne : list[cur]){
                int next = ne.target;
                float dist = ne.dist;

                //대포를 이용한다(출발점과 도착점에서는 대포를 이용못한다)
                //대포와 다음 도착점의 거리가 50보다 작으면 대포를 타고 도착점까지 되돌아간다.
                if(cur > 0 && cur <= n){
                    if(dist >= 50) {
                        float nSec = sec + 2 + (dist - 50) / 5.0f;

                        if (time[next] > nSec) {
                            time[next] = nSec;
                            Q.add(new Edge(next, 0, nSec));
                        }
                    }
                    else{
                        float nSec = sec + 2 + (50 - dist) / 5.0f;

                        if (time[next] > nSec) {
                            time[next] = nSec;
                            Q.add(new Edge(next, 0, nSec));
                        }
                    }
                }

                //오직 걸어간다
                float nSec = sec + (dist / 5.0f);
                if(time[next] > nSec){
                    time[next] = nSec;
                    Q.add(new Edge(next, 0, nSec));
                }
            }

목적지가 50m보다 짧을 때와 50m이상일 때의 계산법이 다름에 주의한다.

# Code </>

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

    static class Vertex{
        float y, x;
        int idx;

        public Vertex(float y, float x, int idx){
            this.y=y;
            this.x=x;
            this.idx=idx;
        }
    }
    static class Edge{
        int target;
        float dist, sec;

        public Edge(int tg, float d, float sec){
            target = tg;
            dist = d;
            this.sec = sec;
        }
    }
    static final int INF = 1000000000;
    static List<Edge>[] list = new ArrayList[102];
    static final float[] time = new float[102];

    static float getDist(Vertex a, Vertex b){

        return (float) Math.sqrt( Math.pow(a.y - b.y, 2) + Math.pow(a.x - b.x, 2) );
    }

    static void Dijkstra(int n){

        Queue<Edge> Q = new PriorityQueue<>((a, b) -> (int) (a.sec - b.sec));
        time[0] = 0;

        Q.add(new Edge(0, 0, 0));

        while(!Q.isEmpty()){
            Edge e = Q.poll();

            int cur = e.target;
            float sec = e.sec;

            if(time[cur] < sec) continue;

            for(Edge ne : list[cur]){
                int next = ne.target;
                float dist = ne.dist;

                //대포를 이용한다(출발점과 도착점에서는 대포를 이용못한다)
                //대포와 다음 도착점의 거리가 50보다 작으면 대포를 타고 도착점까지 되돌아간다.
                if(cur > 0 && cur <= n){
                    if(dist >= 50) {
                        float nSec = sec + 2 + (dist - 50) / 5.0f;

                        if (time[next] > nSec) {
                            time[next] = nSec;
                            Q.add(new Edge(next, 0, nSec));
                        }
                    }
                    else{
                        float nSec = sec + 2 + (50 - dist) / 5.0f;

                        if (time[next] > nSec) {
                            time[next] = nSec;
                            Q.add(new Edge(next, 0, nSec));
                        }
                    }
                }

                //오직 걸어간다
                float nSec = sec + (dist / 5.0f);
                if(time[next] > nSec){
                    time[next] = nSec;
                    Q.add(new Edge(next, 0, nSec));
                }
            }
        }
    }

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

        Vertex[] vertices = new Vertex[102];
        //출발점, 도착점
        for(int i=0; i<2; i++){
            st = new StringTokenizer(br.readLine());
            float x = Float.parseFloat(st.nextToken());
            float y = Float.parseFloat(st.nextToken());
            vertices[i] = new Vertex(y, x, i);
        }

        int n = Integer.parseInt(br.readLine());

        vertices[n+1] = new Vertex(vertices[1].y, vertices[1].x, n+1);
        //대포의 위치와 인덱스 (출발점 인덱스: 0, 도착점 인덱스: n+1)
        for(int i=1; i<=n; i++){
            st = new StringTokenizer(br.readLine());
            float x = Float.parseFloat(st.nextToken());
            float y = Float.parseFloat(st.nextToken());
            vertices[i] = new Vertex(y, x, i);
        }

        //인접리스트 구현
        for(int i=0; i<=n+1; i++){
            time[i] = INF;
            list[i] = new ArrayList<>();
            for(int j=0; j<=n+1; j++){

                if(i == j) continue;
                float dist = getDist(vertices[i], vertices[j]);
                list[i].add(new Edge(j, dist, 0));
            }
        }

        Dijkstra(n);

        System.out.println(time[n+1]);
    }
}
반응형

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

[백준] 14716번 : 현수막  (0) 2021.03.19
[백준] 3187번 : 양치기 꿍  (0) 2021.03.19
[백준] 6087번 : 레이저 통신  (0) 2021.03.18
[백준] 13424번 : 비밀 모임  (0) 2021.03.17
[백준] 10423번 : 전기가 부족해  (0) 2021.03.17
Comments