신호 라우팅 풀이

문제에서 주의할 점
  • 최악의 case: node 수 10000, edge 수 20000
    • 2차원 배열로 graph정보를 표현하면 10000 * 10000 = 1억 (약 1초)
    • 따라서 graph을 인접행렬이나, hash-map와 같이 다른 형태의 표현이 필요.
      • node 10000 + edge 20000 해서 3만 정도의 루프로 graph 표현
  • 간선의 dist값(거리값) 이 이 문제에서는 noise로 되어 있고, 증폭 (곱셉) 연산을 필요로 함
    • double 형 사용이 필요
    • 누적테이블에서, 비교시 덧셈이 아니라 곱셉을 한다음 비교 필요.
    • 최초 노드 (시작노드)를 0 이 아니라 1로 초기화 필요. (0을 곱하면 0이되니까....)
  • 시작 노드 0 으로 고정, 원하는 답(target)노드는 마지막 노드로 고정
  • 출력시 소수점 밑 열자리까지 출력하기를 원함 (System.out.printf("%.10f", result)) 포멧팅 필요

최단경로를 찾는 문제, 음수는 없고, 시작 -> 끝 이 있음으로, 다익스트라로 풀이 가능

풀이코드

Java로 풀이함

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

class NoiseCalc {
    int nodeNum;
    ArrayList<ArrayList<Edge>> nodeList;
    int visited[], path[];
    double noiseVal[];
    double INFINITY = Double.MAX_VALUE;
    int VISITED = 1;

    public NoiseCalc(int nodeNum, ArrayList<ArrayList<Edge>> nodeList) {
        super();
        this.nodeNum = nodeNum;
        this.nodeList = nodeList;

        this.visited = new int[nodeNum];
        this.noiseVal = new double[nodeNum];
        Arrays.fill(this.noiseVal, INFINITY);
        this.path = new int[nodeNum];
        Arrays.fill(this.path, -1);
    }

    public double runCalc() {
        // start 는 0번 node로 고정
        int START_NODE_ID = 0;

        this.noiseVal[START_NODE_ID] = 1; // 여기를 1로 하면 곱셉해도 자기자신
        this.path[START_NODE_ID] = 0;

        PriorityQueue<Node> q = new PriorityQueue<Node>();
        q.offer(new Node(START_NODE_ID, this.noiseVal[START_NODE_ID]));

        while (!q.isEmpty()) {
            Node n = q.poll();

            // 가지치기, q에서 꺼내온 노드의 Noise누적값이 기록된거보다 크면, 방문할 필요가 없음.
            if (n.noise > this.noiseVal[n.id]) {
                continue;
            }

            // 현재 노드에서 방문 가능한 노드를 모두 체크,
            // 즉 현재 노드에서 방문가능한 edge을 모두 체크
            ArrayList<Edge> neerList = this.nodeList.get(n.id);
            for (int i = 0; i < neerList.size(); i++) {
                Edge edge = neerList.get(i);

                double nuVal  = this.noiseVal[edge.endNodeId];
                double newVal;

                newVal = this.noiseVal[n.id] * edge.noiseVal;

                if (nuVal > newVal) { // 더 최적값이 있으면.
                    // 누적테이블 갱신
                    this.noiseVal[edge.endNodeId] = newVal;

                    // 경로 갱신
                    this.path[edge.endNodeId] = n.id;

                    // 해당 노드는 큐에 넣어서, 그 노드에서 부터 방문하는 곳을 계산해야함
                    q.offer(new Node(edge.endNodeId, newVal));
                }
            }
        }

        return this.noiseVal[this.nodeNum - 1];
    }
}

class Node implements Comparable<Node> {
    public int id;
    public double noise;

    Node(int id, double noise) {
        this.id = id;
        this.noise = noise;
    }

    @Override
    public int compareTo(Node o) {
        return this.noise <= o.noise ? -1 : 1;
    }

    @Override
    public String toString() {
        return "Node [id=" + id + ", noise=" + noise + "]";
    }
}

class Edge {
    public int startNodeId, endNodeId;
    public double noiseVal;

    public Edge(int sNodeId, int eNodeId, double noiseVal) {
        this.startNodeId = sNodeId;
        this.endNodeId = eNodeId;
        this.noiseVal = noiseVal;
    }

    public String toString() {
        return "(" + this.startNodeId + "->" + this.endNodeId + ") : [" + this.noiseVal + "]";
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        InputStreamReader fr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(fr);

        int testCaseNumber = Integer.parseInt(br.readLine());
        for (int i = 0; i < testCaseNumber; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());

            int nodeNum = Integer.parseInt(st.nextToken());
            int edgeNum = Integer.parseInt(st.nextToken());

            ArrayList<ArrayList<Edge>> nodeList = new ArrayList<ArrayList<Edge>>(nodeNum);
            // 그래프를 만드는데 최악의 경우 3만번 정도...
            for (int nIndex = 0; nIndex < nodeNum; nIndex++) { // 10000
                nodeList.add(new ArrayList<Edge>());
            }
            for (int e = 0; e < edgeNum; e++) { // 20000
                StringTokenizer edgeStrToken = new StringTokenizer(br.readLine());

                int nodeAId = Integer.parseInt(edgeStrToken.nextToken());
                int nodeBId = Integer.parseInt(edgeStrToken.nextToken());
                double noiseVal = Double.parseDouble(edgeStrToken.nextToken());

                ArrayList<Edge> nodeAEdges = nodeList.get(nodeAId);
                ArrayList<Edge> nodeBEdges = nodeList.get(nodeBId);

                nodeAEdges.add(new Edge(nodeAId, nodeBId, noiseVal));
                nodeBEdges.add(new Edge(nodeBId, nodeAId, noiseVal));
            }

            NoiseCalc calc = new NoiseCalc(nodeNum, nodeList);
            double result = calc.runCalc();

            System.out.printf("%.10f\n", result);
        }

        fr.close();
        br.close();
    }

}

results matching ""

    No results matching ""