1238번: 파티

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어

www.acmicpc.net

 

 

 

 


 

 

  • 풀이

 

X번 마을을 제외한 모든 마을에 있는 사람이 X번 마을에 방문한 뒤 돌아가는 마을 중 최대값을 출력하면 되는 문제입니다. (단, 모든 마을의 사람은 최단거리로 움직입니다.)

 

처음 문제를 읽고 플로이드와샬을 통해 풀어보려고 했지만 N의 최대값이 1,000이고 시간제한이 1초인 것을 보고 O(N^3)인 플로이드와샬로는 풀지 못한다고 생각하였습니다. 

 

저는 한점을 통해 모든 점으로 가는 최단거리를 찾는 다익스트라 방법을 사용했고 우선순위큐를 사용하는 다익스트라 알고리즘은 O(VlogV)이므로 시간은 충분했습니다. 문제에서 주어지는 입력은 단방향이므로 X마을로 오고, 가는 방법을 구하기위해 a->b로 오는 자료구조 한개, b->a로가는 자료구조 한개를 추가로 사용해서 두번의 다익스트라를 통해 최단거리를 구해주었습니다.

 

 

 

  • 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static int N,M,X,answer;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(answer);
	}

	// 데이터
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		answer = 0;
		N = in.nextInt();
		M = in.nextInt();
		X = in.nextInt();
		ArrayList<Node>[] array = new ArrayList[N+1];
		ArrayList<Node>[] reArray = new ArrayList[N+1];
		for(int i = 1; i <= N; i++)  {
			array[i] = new ArrayList<>();
			reArray[i] = new ArrayList<>();
		}
		
		for(int i = 0 ; i < M; i++) {
			int a = in.nextInt();
			int b = in.nextInt();
			int w = in.nextInt();
			array[a].add(new Node(b, w));
			reArray[b].add(new Node(a, w));
		}
		
		int[] distance = dijkstra(array);
		int[] nDistance = dijkstra(reArray);
		
		for(int i = 1; i <= N; i++) {
			answer = Math.max(answer, distance[i] + nDistance[i]);
		}
	}

	private static int[] dijkstra(ArrayList<Node>[] array) {
		PriorityQueue<Node> pq = new PriorityQueue<>();
        pq.offer(new Node(X, 0));
		
        boolean[] check = new boolean[N + 1];
        int[] distance = new int[N + 1];
        Arrays.fill(distance, 10000000);
       
        distance[X] = 0;
        
        while (!pq.isEmpty()) {
            Node nowNode = pq.poll();
 
            if (check[nowNode.x])  continue;
            
            check[nowNode.x] = true;
            for(int i = 0; i < array[nowNode.x].size(); i++) {
            	Node node = array[nowNode.x].get(i);
            	if (check[node.x] || distance[node.x] <= distance[nowNode.x] + node.distance) continue;
            	
            	distance[node.x] = distance[nowNode.x] + node.distance;
                pq.add(new Node(node.x, distance[node.x]));
            }
        }
		return distance;
		
	}
}

class Node implements Comparable<Node> {
	int x;
	int distance;
	
	public Node(int x, int distance) {
		this.x = x;
		this.distance = distance;
	}

	@Override
	public int compareTo(Node node) {
		// TODO Auto-generated method stub
		return this.distance - node.distance;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

 

5427번: 불

상근이는 빈 공간과 벽으로 이루어진 건물에 갇혀있다. 건물의 일부에는 불이 났고, 상근이는 출구를 향해 뛰고 있다. 매 초마다, 불은 동서남북 방향으로 인접한 빈 공간으로 퍼져나간다. 벽에

www.acmicpc.net

 

 

 

 


 

 

 

 

  • 풀이

 

문제는 어렵기보단 입력값이 크지 않기때문에 문제에 조건대로 구현만 잘하면되는 문제입니다.

 

문제의 조건은 다음과 같습니다.

  • '.': 빈 공간
  • '#': 벽
  • '@': 상근이의 시작 위치
  • '*': 불

의 입력에서 @인 상근이를 벽과 불을 피해서 배열 밖으로 빼낼 수 있으면 최소값 출력, 빼낼 수 없다면 IMPOSSIZBLE을 출력하면 되는 문제입니다. 단, *인 불과 @인 상근이는 1초마다 상,하,좌,우로 1칸씩 움직일 수 있습니다. 또한 불이 불이 먼저 번지기 때문에 상근이는 현재 불이 상, 하, 좌, 우로 퍼진 위치로 갈 수 없고 불은 현재 상근이가 위치한 좌표로 번질 수 있지만 상근이는 움직일 수 있다면 상관없습니다. 여기까지가 문제에 대한 조건들 입니다.

 

 

풀이 방법은 bfs를 사용했고, queue에 현재 저장되어있는 불들을 다 번지게 한 뒤, 상근이를 움직일 수 있게 해주었습니다. 만약, 상근이가 범위 밖으로 갈 수 있을 시 움직인 횟수를 return해주었고 상근이가 더이상 움직일 수 없어서 반복문이 종료되게 될때까지 return하지 못했다면 상근이는 건물을 벗어날 수 없는 것이기 때문에 -1을 return 해주었습니다.

 

 

  • 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static int w, h;
	static StringBuilder sb;
	static char[][] array;
	static boolean[][] check;
	static Queue<Sang> sang;
	static Queue<Node> fire;
	static int[] dx = { 0, 0, -1, 1 };
	static int[] dy = { -1, 1, 0, 0 };

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(sb);
	}

	// 데이터
	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		sb = new StringBuilder();
		int testcase = in.nextInt();
		for (int i = 0; i < testcase; i++) {
			w = in.nextInt();
			h = in.nextInt();
			array = new char[h][w];
			check = new boolean[h][w];
			sang = new LinkedList<>();
			fire = new LinkedList<>();

			for (int a = 0; a < h; a++) {
				String s = in.nextLine();
				for (int b = 0; b < w; b++) {
					array[a][b] = s.charAt(b);
					if (array[a][b] == '*')
						fire.add(new Node(a, b));
					if (array[a][b] == '@')
						sang.add(new Sang(a, b, 0));
				}
			}

			int answer = bfs();
			if (answer == -1) {
				sb.append("IMPOSSIBLE").append("\n");
			} else {
				sb.append(answer).append("\n");
			}
		}

	}

	private static int bfs() {
		while (!sang.isEmpty()) {
			// 불 1초 이동 
			int fireSize = fire.size();
			for (int i = 0; i < fireSize; i++) {
				Node node = fire.poll();

				for (int direction = 0; direction < 4; direction++) {
					int r = node.x + dx[direction];
					int c = node.y + dy[direction];

					if (r < 0 || c < 0 || r >= h || c >= w)
						continue;
					if (array[r][c] == '#' || array[r][c] == '*')
						continue;

					array[r][c] = '*';
					fire.add(new Node(r, c));
				}
			}

			
			// 상근이 1초 이동 
			int sangSize = sang.size();

			for (int i = 0; i < sangSize; i++) {
				Sang temp = sang.poll();
				check[temp.x][temp.y] = true;

				for (int direction = 0; direction < 4; direction++) {
					int r = temp.x + dx[direction];
					int c = temp.y + dy[direction];

					if (r < 0 || c < 0 || r >= h || c >= w)
						return temp.count + 1;
					if (array[r][c] != '.' || check[r][c])
						continue;

					check[r][c] = true;
					sang.add(new Sang(r, c, temp.count + 1));
				}
			}
		}

		return -1;
	}

}

class Node {
	int x;
	int y;

	public Node(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

class Sang {
	int x;
	int y;
	int count;

	public Sang(int x, int y, int count) {
		this.x = x;
		this.y = y;
		this.count = count;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

DNS 란?

  • 도메인 네임 시스템(Domain Name System, DNS)은 호스트의 도메인 이름을 호스트의 네트워크 주소로 바꾸거나 그 반대의 변환을 수행할 수 있도록 하기 위해 개발되었습니다.
  • 쉽게 생각하자면 사용자가 이해할 수 있는 도메인 이름을 기계가 이해할 수 있는 IP로 변환해주는 시스템입니다.

 

 

DNS 구성요소

  • 도메인 네임 스페이스 (Domain Name Space)
    • 주소를 변환 시키기 위해 도메인 네임 스페이스의 트리구조에 대한 정보가 필요. 이 정보를 가진 서버 도메인 이름을 IP주소로 변환하는 것을 네임 서비스
  • 네임 서버 (Name Server)
    • 최상위에 루트 DNS 서버가 존재하고 , 그 하위로 인터넷에 연결된 모든 노드가 연속해서 이어진 계층구조로 구성
  • 리졸버 (Resolver)
    • DNS클라이언트의 요청을 네임 서버로 전달하고 네임 서버로부터 도메인이름과 IP 주소를 받아 클라이언트에게 제공하는 기능을 수행

 

 

 

DNS 동작원리

  1. DNS Query (from Web Browser to Local DNS) : "제가 원하는 웹 사이트의 IP 주소를 알고 계신가요?" Local DNS 서버에게 전달
  2. DNS Response (from Local DNS to Web Browser) : 만약 Local DNS 서버 캐시에 해당 Domain에 대한 IP가 있다면, 바로 IP 주소를 전달
  3. DNS Query (from Local DNS to Root DNS) : Local DNS 서버 캐시에 해당 Domain이 없다면, "제가 원하는 웹 사이트의 IP 주소를 알고 계신가요?" Root DNS서버에게 전달
  4. DNS Response (from Root DNS to Local DNS) : "저는 모르지만 , Com 도메인을 관리하는 네임서버의 이름과 IP 주소를 알려드릴 테니 거기에 물어보세요"
  5. DNS Query (from Local DNS to com NS) : “ 안녕하세요. www. naver. com의 IP 주소를 알고 계신가요?"
  6. DNS Response (from com NS to Local DNS) : "저는 모르지만 , Com 도메인을 관리하는 네임서버의 이름과 IP 주소를 알려드릴 테니 거기에 물어보세요"
  7. DNS Query (from Local DNS to naver. com NS) : “ 안녕하세요. www. Naver .com의 IP 주소를 알고 계신가요?"
  8. DNS Response (from naver .com NS to Local DNS) : "저는 모르지만 해당 웹은 www. g.naver. com이라는 이름으로 통해요. g.naver .com 도메인을 관리하는 네임서버의 이름과 IP 주소를 알려드릴테니 거기에 물어보세요"
  9. DNS Query (from Local DNS to g.naver. com NS) : “ 안녕하세요. www. g.naver. com의 IP 주소를 알고 계신가요?"
  10. DNS Response (from g.naver .com NS to Local DNS) : " 네 www. g.naver .com의 IP 주소는 222.222.222.22와 333.333.333.33입니다"
  11. DNS Response (from Local DNS to Web Browser) : "네 www. naver .com의 IP 주소는 222.222.222.22와 333.333.333.33입니다"
  12. 그 후, 3-way-handshake를 통해 통신하고 4-way-handshake를 통해 통신을 종료합니다.

'Network' 카테고리의 다른 글

[Network] OAuth  (0) 2021.10.27
[Network] 메세지 전송방식(유니캐스트, 멀티캐스트, 브로드캐스트)  (0) 2021.10.27
[Network] REST와 RESTful  (0) 2021.10.22
[Network] 쿠키와 세션  (0) 2021.10.21
[Network] HTTP Method  (0) 2021.10.21

 

 

코딩테스트 연습 - 12주차

XX게임에는 피로도 시스템(0 이상의 정수로 표현합니다)이 있으며, 일정 피로도를 사용해서 던전을 탐험할 수 있습니다. 이때, 각 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"와 던

programmers.co.kr

 

 


 

 

  • 풀이

 

처음엔 정렬한 후 풀어보려고했지만 입력값이 까다로워서 정확한 답을 구현할 수 없었습니다.

 

던전의 수가 최대 8개로 많지 않기때문에 완탐을 했습니다.

dfs 방식으로 완전 탐색 했습니다.

 

 

  • 코드

 

import java.util.*;

class Solution {
    static boolean[] check;
    static int answer;
    
    public int solution(int k, int[][] dungeons) {
        check = new boolean[dungeons.length];
        answer = 0;
        
        for(int i = 0; i < dungeons.length; i++){
            if(dungeons[i][0] > k) continue;
            
            check[i] = true;
            dfs(k-dungeons[i][1], dungeons, 1);
            check[i] = false;
        }
        
        return answer;
    }
    
    private static void dfs(int k, int[][] dungeons, int count){
        answer = Math.max(answer, count);
        
       for(int i = 0; i < dungeons.length; i++){
            if(dungeons[i][0] > k || check[i]) continue;
            
            check[i] = true;
            dfs(k-dungeons[i][1], dungeons, count+1);
            check[i] = false;
        }
    }
}

 

 

1167번: 트리의 지름

트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2 ≤ V ≤ 100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. 정점 번호는 1부터 V까지

www.acmicpc.net

 

 

 

 


 

 

 

  • 풀이

 

트리의 자료구조 중 임의의 두점의 거리가 가장 먼 거리를 출력해주면되는 문제입니다.

 

먼저, 트리의 연결은 ArrayList 배열을 통해 연결해 주었습니다.

 

그 후, 트리 탐색은 dfs방식을 사용했습니다.

 

첫번째 풀이는 모든 노드들에서 시작해서 모든 노드들을 돌면서 가장 거리의 합이 높은 노드 길이의 합을 게속 초기화 시켜주는 방식을 사용했습니다. 하지만 해당 코드는 시간 초과가 떴습니다. 해당 문제의 제한 시간은 2초이고 최대 노드의 수는 100,000이기때문이였습니다.

 

바꿀 방법을 생각해보니 모든 노드의 시작부터 할 필요가 없었습니다. 실제로 단 두 번의 시작노드를 통해 정답을 뽑아낼 수 있습니다. 단 두번으로 할 수 있는 근거는 트리입니다. 모든 노드들은 연결되어 있습니다. 한 노드에서 시작해서 가장 먼 노드를 초기화시켜준 뒤 가장 먼 노드부터 시작해서 가장 먼 노드를 구해주면 값을 뽑아낼 수 있습니다. 

 

모두 이어져있기 때문에 한 노드에서 가장 먼 노드를 구하면 가장 먼노드부터 그전에 시작한 노드까지의 합과 그전에 시작한 노드부터 두번째로 먼 노드의 합까지 더할 수 있기 때문입니다.

 

 

  • 시간초과 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static ArrayList[] node;
	static int answer;
	static boolean[] check;
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		SetData();
		System.out.println(answer);
	}

	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		int V = in.nextInt();
		node = new ArrayList[V+1];
		check = new boolean[V+1];
		answer = 0;
		
		for(int i = 1; i <= V ;i++)
			node[i] = new ArrayList<Node>();
		
		for(int i = 0; i < V; i++) {
			int now = in.nextInt();
			
			while(true) {
				int nodeNumber = in.nextInt();
				if(nodeNumber == -1) break;
				int distance = in.nextInt();
				
				node[now].add(new Node(nodeNumber, distance));
			}
		}
		
		for(int i = 1; i <= V; i++) {
			check[i] = true;
			bfs(i, 0);
			check[i] = false;
		}
	}
	
	private static void bfs(int now, int sum) {
		if(answer < sum) {
			answer = sum;
		}
		
		for(int i = 0; i < node[now].size(); i++) {
			Node temp = (Node) node[now].get(i);
			
			if(check[temp.x]) continue;
			
			check[temp.x] = true;
			bfs(temp.x, sum + temp.distance);
			check[temp.x] = false;
		}
	}
}

class Node {
	int x;
	int distance;
	
	public Node(int x, int distance) {
		this.x = x;
		this.distance = distance;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

 

 

  • 통과 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static ArrayList[] node;
	static int answer, max;
	static boolean[] check;
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		SetData();
		System.out.println(answer);
	}

	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		int V = in.nextInt();
		node = new ArrayList[V+1];
		check = new boolean[V+1];
		answer = 0;
		max = 0;
		
		for(int i = 1; i <= V ;i++)
			node[i] = new ArrayList<Node>();
		
		for(int i = 0; i < V; i++) {
			int now = in.nextInt();
			
			while(true) {
				int nodeNumber = in.nextInt();
				if(nodeNumber == -1) break;
				int distance = in.nextInt();
				
				node[now].add(new Node(nodeNumber, distance));
			}
		}
		
		check[1] = true;
		bfs(1, 0);
		check[1] = false;
		
		check[max] = true;
		bfs(max, 0);
	}
	
	private static void dfs(int now, int sum) {
		if(answer < sum) {
			answer = sum;
			max = now;
		}
		
		for(int i = 0; i < node[now].size(); i++) {
			Node temp = (Node) node[now].get(i);
			
			if(check[temp.x]) continue;
			
			check[temp.x] = true;
			bfs(temp.x, sum + temp.distance);
			check[temp.x] = false;
		}
	}
}

class Node {
	int x;
	int distance;
	
	public Node(int x, int distance) {
		this.x = x;
		this.distance = distance;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

 

1939번: 중량제한

첫째 줄에 N, M(1 ≤ M ≤ 100,000)이 주어진다. 다음 M개의 줄에는 다리에 대한 정보를 나타내는 세 정수 A, B(1 ≤ A, B ≤ N), C(1 ≤ C ≤ 1,000,000,000)가 주어진다. 이는 A번 섬과 B번 섬 사이에 중량제한이

www.acmicpc.net

 

 


 

 

  • 풀이

 

처음에 백트래킹으로 풀려고 했지만 시간초과가 떴습니다.

M값은 10만이 최대이다. 시간초과가 왜??나는지에 대해서 아직 정확하게 모르겠습니다..

전체적으로 보았을 때 a에서 b로 가는 노드 중 가장 경로 중 가장 작은 값이 가장 큰 경로를 찾으면 되는 문제라 a에서 b로가는 모든 경로를 한번씩만 훑으면 더 빠른것이 아닌가??라는 생각이 들었습니다... (물론, a와 b가 가장 작은 값으로 한번에 연결되어있다면 굳이 모든 노드를 다 돌을 필요가 없지만 이러한 경우의 수 빼고는 다 돌아야되는 것이 맞는 것 아닌가...??!)

 

일단, 해결 풀이 방법은 이분탐색과 bfs를 사용했습니다. (알고리즘 분류를 통해 해결 방법을 찾았습니다.)

이분탐색의 기준은 weight으로 입력 중 최대 중량을 초기화시켜준 뒤 left = 0, right = 최대중량으로 이분탐색을 하며 bfs를 돌았습니다. mid값 보다 bfs를 돌며 큰 값이 있는 경우는 ritght를 mid -1로 초기화 시켜주고 문제가 없을 시 left를 mid + 1로 초기화시켜주었습니다.

 

 

 

  • 시간초과 코드 (백트래킹) 

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static int N, M, answer;
	static ArrayList[] arrayList;
	static boolean[] check;

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		SetData();
		System.out.println(answer);
	}

	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		N = in.nextInt();
		M = in.nextInt();
		answer = 0;
		arrayList = new ArrayList[N+1];
		check = new boolean[N+1];
		
		for(int i = 1; i <= N; i++)
			arrayList[i] = new ArrayList<Node>();
		
		for(int i = 0; i < M; i++) {
			int a = in.nextInt();
			int b = in.nextInt();
			int weight = in.nextInt();
			
			arrayList[a].add(new Node(b, weight));
			arrayList[b].add(new Node(a, weight));
		}
		
		int x = in.nextInt();
		int y = in.nextInt();
		check[x] = true;
		for(int i = 0; i < arrayList[x].size(); i++) {
			Node node = (Node) arrayList[x].get(i);
			
			check[node.a] = true;
			answer = Math.max(answer, dfs(node.weight, node.a, y));
			check[node.a] = false;
		}
	}
	
	private static int dfs(int min, int index, int b) {
		if(index == b) {
			return min;
		}
		
		for(int i = 0; i < arrayList[index].size(); i++) {
			Node node = (Node) arrayList[index].get(i);
			if(check[node.a]) continue;
			check[node.a] = true;
			min = Math.min(dfs(Math.min(min, node.weight), node.a, b),min);
			check[node.a] = false;
		}
		
		return min;
	}
}

class Node {
	int a;
	int weight;
	
	public Node(int a, int weight) {
		this.a = a;
		this.weight = weight;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

 

 

  • 통과 코드 (이분 탐색)

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static int N, M, answer;
	static ArrayList[] arrayList;
	static boolean[] check;

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		SetData();
		System.out.println(answer);
	}

	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		N = in.nextInt();
		M = in.nextInt();
		answer = 0;
		arrayList = new ArrayList[N+1];
		int max = 0;
		
		for(int i = 1; i <= N; i++)
			arrayList[i] = new ArrayList<Node>();
		
		for(int i = 0; i < M; i++) {
			int a = in.nextInt();
			int b = in.nextInt();
			int weight = in.nextInt();
			
			arrayList[a].add(new Node(b, weight));
			arrayList[b].add(new Node(a, weight));
			max = Math.max(weight, max);
		}
		
		int x = in.nextInt();
		int y = in.nextInt();
		
		int left = 0;
		int right = max;
		while(left<= right) {
			int mid = (left + right) / 2;
			
			check = new boolean[N+1];
			
			if(bfs(x,y,mid)) {
				left = mid + 1;
			} else {
				right = mid - 1;
			}
		}
		
		answer = right;
	}
	
	private static boolean bfs(int start, int end, int weigth) {
		Queue<Integer> queue = new LinkedList<>();
		queue.add(start);
		check[start] = true;
		
		while(!queue.isEmpty()) {
			int d = queue.poll();
			
			if(d == end) {
				return true;
			}
			
			for(int i = 0 ; i < arrayList[d].size(); i++) {
				Node node = (Node) arrayList[d].get(i);
                if (!check[node.a] && weigth <= node.weight) {
                    check[node.a] = true;
                    queue.add(node.a);
                }
            }
		}
		
		return false;
	}
}

class Node {
	int a;
	int weight;
	
	public Node(int a, int weight) {
		this.a = a;
		this.weight = weight;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

 

6064번: 카잉 달력

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 구성된다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터는 한 줄로 구성된다.

www.acmicpc.net

 

 

 

 


 

 

 

  • 풀이

 

처음에 문제풀 때 M*N의 시간복잡도로 풀어 시간초과가 났습니다.

 

해결방법은 유클리드 호제법을 통해 계산해야되는 경우의 수를 최대한 줄여줍니다.

 

해당 방법과 반복문을 최대한으로 줄이기 위해 i*M<lcm의 방식을 사용했습니다.

 

(i*M+x-y) % N ==0 이라면 x 값도 나오고 y 값도 나온다는 것을 의미하기 때문에 index를 초기화 시켜준 뒤 break를 걸어주었습니다. 

 

이런 식의 반복문을 사용한다면 반복문의 최대 반복수는 lcm%M 번으로 줄일 수 있습니다.

 

  • 코드

 

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class Main {
	static StringBuilder sb;

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		SetData();
		System.out.println(sb);
	}

	private static void SetData() throws Exception {
		InputReader in = new InputReader(System.in);

		int testcase = in.nextInt();
		sb = new StringBuilder();

		for (int i = 0; i < testcase; i++) {
			int M = in.nextInt();
			int N = in.nextInt();
			int x = in.nextInt();
			int y = in.nextInt();
			int lcm = M * N / gcd(M, N);

			sb.append(FindValue(lcm, M, N, x, y)).append("\n");
		}
	}

	private static int gcd(int x, int y) {
		if (x % y == 0)
			return y;

		return gcd(y, x % y);
	}

	private static int FindValue(int lcm, int M, int N, int x, int y) {
		int answer = -1;
		for (int i = 0; i * M < lcm; i++) {
			if ((i * M + x - y) % N == 0) {
				answer = i * M + x;
				break;
			}
		}
		return answer;
	}
}

class InputReader {
	private final InputStream stream;
	private final byte[] buf = new byte[8192];
	private int curChar, snumChars;

	public InputReader(InputStream st) {
		this.stream = st;
	}

	public int read() {
		if (snumChars == -1)
			throw new InputMismatchException();
		if (curChar >= snumChars) {
			curChar = 0;
			try {
				snumChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (snumChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c)) {
			c = read();
		}
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int[] nextIntArray(int n) {
		int a[] = new int[n];
		for (int i = 0; i < n; i++) {
			a[i] = nextInt();
		}
		return a;
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	private boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}
}

REST와 RESTful

  • 웹에 존재하는 사진, 영상, DB 자원 등 모든 자원에게 고유한 URI를 부여해 GET, POST, DELETE, PUT 명령어를 이용해 활용하는 것을 의미합니다.

 

Rest API의 네 가지 기능과 특징에 대해 말씀해주세요.

  • GET : GET를 통해 해당 리소스를 조회하고 요청에 대한 자세한 정보를 가져옵니다
  • POST : POST를 통해 해당 URI를 요청하면 리소스를 생성합니다
  • DELETE : DELETE를 통해 리소스를 삭제합니다
  • PUT : PUT를 통해 해당 리소스를 수정합니다. 여러 번 수행해도 결과가 같은 경우 사용합니다

 

URL과 URI의 차이

  • URI는 인터넷 상의 자원을 식별하기 위한 문자열의 구성입니다. URL은 인터넷 상의 자원 위치를 나타내며 URI에 포함되는 개념입니다.

 

REST 란?

    • Representational State Transfer(대표적인 상태 전달)
    • 월드 와이드 웹(WWW)과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 개발 아키텍쳐의 한 형식
    • REST는 기본적으로 웹의 기존 기술과 HTTP 프로토콜을 그대로 활용하기 때문에 웹의 장점을 최대한 활용할 수 있는 아키텍쳐 스타일
    • REST는 네트워크 상에서 Client와 Server가 통신하는 방식 중 하나입니다.
    • HTTP URI를 통해 자원을 명시하고, HTTP 메소드를 통해 해당 자원에 대한 CRUD Operation(Create, Read, Update, Delete)을 적용하는 것을 의미합니다.
    • 즉, REST는 자원 기반 구조 설계의 중심에 Resource가 있고 HTTP 메소드를 통해 Resource를 처리하도록 설계된 아키텍쳐입니다.
    • 웹 사이트의 이미지, DB, 텍스트 내용 등의 모든 자원에 고유한 ID인 HTTP URI를 부여합니다.
    • 장점
      1. 여러 가지 서비스 디자인에서 생길 수 있는 문제를 최소화해줍니다.
      2. Hypermedia API의 기본을 충실히 지키면서 범용성을 보장합니다
      3. HTTP 프로토콜의 표준을 최대한 활용하여 여러 추가적인 장점을 함께 가져갈 수 있게 해줍니다.
    • 단점
      1. 브라우저를 통해 테스트 할 일이 많은 서비스라면 쉽게 고칠 수 있는 URL보다 헤더 값이 더 어렵게 느껴질 수 있습니다.
      2. 구형 브라우저가 아직 제대로 지원해주지 않는 부분이 존재합니다. (PUT, DELETE를 사용하지 못함)
    • REST가 필요한 이유
      1. 애플리케이션 분리 및 통합
      2. 다양한 클라이언트의 등장
      3. 즉, 최근의 서버 프로그램은 다양한 브라우저와 안드로이드, 아이폰과 같은 모바일 디바이스에서도 통신을 할 수 있어야 함
    • REST 구성 요소
      1. 자원(Resource) : URI
        • 모든 자원에 고유한 ID가 존재하고, 이 자원은 서버에 존재합니다.
        • 자원을 구별하는 아이디는 'groups/:group_id'와 같은 HTTP URI 입니다.
        • Client는 URI를 통해 자원을 지정하고 해당 자원 상태에 대한 조작을 서버에 요청합니다.
      2. 행위(Verb) : HTTP 메소드
        • HTTP 프로토콜은 메소드를 사용합니다.
        • HTTP 프로토콜은 POST, GET, PUT, DELETE, HEAD와 같은 메소드를 제공합니다.
      3. 표현(Representation Of Resource)
        • Client가 자원 상태에 대한 조작을 서버에 요청하면 서버는 요청에 대한 적절한 응답을 보냅니다.
        • REST에서 하나의 자원은 JSON, XML, TEXT, RSS 등 여러 형태의 표현으로 나타낼 수 있습니다.
        • JSON 혹은 XML을 통해 자원을 주고받는 것이 일반적입니다.
    • REST 특징
      • Server-Client구조
      • Stateless (무상태)
      • Cacheable (캐시 처리 가능)
      • Layered System (계층화)
      • Code-On-Demand (optional)
      • Uniform interface (인터페이스 일관성)

 

 

RESTful 이란?

  • 개념
    • RESTful이란 일반적으로 REST란 아키텍처를 구현하는 웹 서비스를 나타내기 위해 사용되는 용어입니다.
    • 즉, REST 원리를 따르는 시스템은 RESTful이란 용어로 지칭된다. RESTful이란 REST를 REST답게 쓰기 위한 방법으로 누군가가 공식적으로 발표한 것은 아닙니다.
  • 목적
    • 이해하기 쉽고 사용하기 쉬운 REST API를 만드는 것
    • RESTful API를 구현하는 근본적인 목적이 퍼포먼스 향상에 있는게 아니라, 일관적인 컨벤션을 통한 API의 이해도 및 호환성을 높여주는게 주 동기입니다. 그렇기때문에 퍼포먼스가 중요한 상황에서 굳이 REST API를 구현할 필요는 없습니다.
  • RESTful하지 못한 경우
    • Ex1) CRUD 기능을 모두 POST로 처리하는 API
    • Ex2) route에 resource, id 외의 정보가 들어가는 경우(/students/updateName)

 

 

REST API

  • REST기반으로 API를 구현하는 것
  • 최근 OpenAPI(누구나 사용할 수 있도록 공개된 API : 네이버 맵, 공공데이터 등등), 마이크로 서비스(하나의 큰 애플리케이션을 여러개의 작은 애플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍쳐) 등을 제공하는 업체 대부분은 REST API를 제공합니다.
  • 특징
    • 사내 시스템들도 REST 기반으로 시스템을 분산해 확장성과 재사용성을 높여 유지보수 및 운용을 편리하게 할 수 있습니다.
    • REST는 HTTP 표준을 기반으로 구현하므로 HTTP를 지원하는 프로그램 언어로 클라이언트, 서버를 구현할 수 있습니다.
    • 즉, REST API를 제작하면 델파이 클라이언트 뿐 아니라 자바, C#, 웹 등을 이용해 클라이언트를 제작할 수 있습니다.
  • 설계 (기본 규칙)
    1. URI는 정보의 자원을 표현해야 합니다.
      • resource는 동사보다 명사를 사용합니다.
      • resource는 영어 소문자 복수형을 사용하여 표현합니다.
      • Ex) 'GET /Member/1' -> 'GET /member/1'
    2. 자원에 대한 행위는 HTTP 메소드로 표현합니다.
      • URI에 HTTP 메소드가 들어가면 안됩니다.
      • Ex) 'GET /members/delete/1' -> 'DELETE /members/1'
      • URI에 행위에 대한 동사 표현이 들어가면 안됩니다.
      • Ex) 'GET /members/show/1' -> 'GET /members/1'
      • Ex) 'GET /members/insert/1' -> 'POST /members/1'
  • 설계 규칙
    1. 슬래시 구분자(/)는 계층 관계를 나타내는데 사용합니다.
    2. URI에 마지막 문자로 구분자(/)를 포함하지 않습니다.
      • URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르면 URI도 달라져야함
      • Ex) 'http://restapi.example.com/houses/apartments/ (X)'
      • REST API는 분명한 URI를 만들어 통신을 해야 하기 때문에 혼동을 주지 않도록 URI 경로의 마지막에는 슬래시(/)를 사용하지 않음
    3. 하이픈(-)은 URI가독성을 높이는데 사용합니다.
      • 불가피하게 긴 URI경로를 사용하게 된다면 하이픈을 사용해 가독성을 높임
    4. 밑줄(_)은 URI에 사용하지 않습니다.
      • 밑줄은 보기 어렵거나 밑줄 때문에 문자가 가려지기도 하므로 가독성을 위해 밑줄은 사용하지 않음
    5. URI 경로에는 소문자가 적합합니다.
      • URI 경로에 대문자 사용은 피하도록 함
      • RFC 3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문
    6. 파일확장자는 URI에 포함하지 않습니다.
      • REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않음
      • Ex) `http://restapi.example.com/members/soccer/345/photo.jpg (X)`
      • Ex) `GET / members/soccer/345/photo HTTP/1.1 Host: restapi.example.com Accept: image/jpg (O)`
      • Accept header를 사용
    7. 리소스 간에는 연관관계가 있는 경우
      • /리소스명/리소스 ID/관계가 있는 다른 리소스명
      • Ex) `GET : /users/{userid}/devices (일반적으로 소유 ‘has’의 관계를 표현할 때)`
    8. :id는 특정 resource를 나타내는 고유 값
      • Ex) student를 생성하는 route: POST /students 
      • Ex) id=12인 student를 삭제하는 route: DELETE /students/12
  •  

 

 

'Network' 카테고리의 다른 글

[Network] 메세지 전송방식(유니캐스트, 멀티캐스트, 브로드캐스트)  (0) 2021.10.27
[Network] DNS 동작원리  (0) 2021.10.25
[Network] 쿠키와 세션  (0) 2021.10.21
[Network] HTTP Method  (0) 2021.10.21
[Network] HTTP와 HTTPS  (0) 2021.10.21

+ Recent posts