11-04 13:28
- Today
 
- Total
 
													Link
													
												
											
												
												
											
									개발하는 고라니
[백준] 10473번 : 인간 대포 본문
반응형
    
    
    
  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