728x90
반응형

 

 

1976번: 여행 가자

동혁이는 친구들과 함께 여행을 가려고 한다. 한국에는 도시가 N개 있고 임의의 두 도시 사이에 길이 있을 수도, 없을 수도 있다. 동혁이의 여행 일정이 주어졌을 때, 이 여행 경로가 가능한 것인

www.acmicpc.net

 

 

문제 설명

 

동혁이는 친구들과 함께 여행을 가려고 한다. 한국에는 도시가 N개 있고 임의의 두 도시 사이에 길이 있을 수도, 없을 수도 있다. 동혁이의 여행 일정이 주어졌을 때, 이 여행 경로가 가능한 것인지 알아보자. 물론 중간에 다른 도시를 경유해서 여행을 할 수도 있다. 예를 들어 도시가 5개 있고, A-B, B-C, A-D, B-D, E-A의 길이 있고, 동혁이의 여행 계획이 E C B C D 라면 E-A-B-C-B-C-B-D라는 여행경로를 통해 목적을 달성할 수 있다.

도시들의 개수와 도시들 간의 연결 여부가 주어져 있고, 동혁이의 여행 계획에 속한 도시들이 순서대로 주어졌을 때 가능한지 여부를 판별하는 프로그램을 작성하시오. 같은 도시를 여러 번 방문하는 것도 가능하다.

 

 

입력

 

첫 줄에 도시의 수 N이 주어진다. N은 200 이하이다. 둘째 줄에 여행 계획에 속한 도시들의 수 M이 주어진다. M은 1000 이하이다. 다음 N개의 줄에는 N개의 정수가 주어진다. i번째 줄의 j번째 수는 i번 도시와 j번 도시의 연결 정보를 의미한다. 1이면 연결된 것이고 0이면 연결이 되지 않은 것이다. A와 B가 연결되었으면 B와 A도 연결되어 있다. 마지막 줄에는 여행 계획이 주어진다. 도시의 번호는 1부터 N까지 차례대로 매겨져 있다.

 

 

 

출력

 

첫 줄에 가능하면 YES 불가능하면 NO를 출력한다.

 

 

 

풀이

 

 

문제 설명에 나오는 그림이고, 여행 계획이 "E C B C D"라고 나옵니다.

 

그리고 갈 수 있는 방법은 "E-A-B-C-B-C-B-D" 이와 같습니다. 즉 연결이 되었다면 그 사이를 움직이는 것은 문제가 없다는 것을 나타냅니다.

 

정점 사이의 연결은 union-find를 이용해 확인하고, 문제를 풀어나갈 수 있습니다.

 

따라서 문제 접근은 입력에서 "1"로 이루어져 있는 연결에 대해 union을 진행해줍니다.

 

그리고 최종적으로 find를 통해 여행계획의 정점이 서로 다 연결되었는지 확인만 해주면 됩니다.

 


1. 연결된 정점에 대해서 union 진행

 

2. 가고 싶은 정점에 대해 find 진행

 

3. find한 결과가 다 같은지 확인

 

 

최종 코드

 

 

import java.io.*;
import java.util.*;

public class Main {
	static int N,M;
	static int parent[];
	
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer tokenizer;
		
		N = Integer.parseInt(br.readLine());
		M = Integer.parseInt(br.readLine());
		
		parent = new int[N+1];
		for(int i = 1; i <= N; i++) {
			parent[i] = i;
		}
		for(int i = 1; i <= N; i++) {
			tokenizer = new StringTokenizer(br.readLine());
			
			for(int j = 1; j <= N; j++) {
				int t = Integer.parseInt(tokenizer.nextToken());
				
				if(t==1) {
					union(i,j); // 들어오는 정점 연결
				}
			}
		}
		
		boolean result = true;
		tokenizer = new StringTokenizer(br.readLine());
		int start = find(Integer.parseInt(tokenizer.nextToken()));
		for(int i = 1; i < M; i++) {
        	// 가야할 정점끼리 연결이 되었는지 확인
			if(start != find(Integer.parseInt(tokenizer.nextToken()))) {
				result = false;
			}
		}
		
        // 연결이 되었다면
		if(result == true) {
			System.out.println("YES");
		}
        // 연결이 되지 않았다면
        else {
			System.out.println("NO");
		}
		
		
	}
	static void union(int a, int b) {
		int aRoot = find(a);
		int bRoot = find(b);
		
		if(aRoot < bRoot) {
			parent[aRoot] = bRoot;
		}
		else {
			parent[bRoot] = aRoot;
		}
		
	}
	static int find(int n) {
		if(parent[n] == n) {
			return n;
		}
		else return parent[n] = find(parent[n]);
	}
	
}

 

 

반응형
728x90
반응형

<목차>

1.정렬이란?

2. selection sort(선택정렬)

3. insertion sort(삽입정렬)

4. shell sort(셸정렬)

 

정렬이란?


자료를 일정한 기준에 따라 나열하는 것

큰 순서대로 정렬을 하는 오름차순과 작은 순서대로 정렬하는 내림차순이 존재

이와 관련된 여러 정렬 알고리즘이 존재

 

 

 

selection sort(선택정렬)


선택정렬이란 가장 작은(큰) 데이터를 찾아 가장 앞에 있는 데이터와 교환화는 방식

※데이터가 정렬이 되어 있든 없든 상관없이 일정한 시간을 가진다.

 

<코드>

public class selection_sort {
	
	public static void main(String args[]) {
		int[] arr = {1,5,4,2,7};
		int min;
		int i,j;
		for(i=0; i<arr.length-1; i++) {
			min = i;
			for(j=i+1; j<arr.length; j++) {
				if(arr[j]<arr[min])
					min=j;
			}
			swap(arr,i,min);	
		}
		for(i=0; i<arr.length; i++)
			System.out.print(arr[i]);
	}
	static void swap(int[] arr, int a,int b) {
		int temp;
		temp =arr[a];
		arr[a]=arr[b];
		arr[b]=temp;
		
	}

}

 

 

 

insertion sort(삽입정렬)


삽입 정렬이란 임의의 데이터를 이미 정렬된 부분의 적절한 위치에 삽입해 가며 정렬하는 방식

 

※ 데이터가 이미 정렬되어 있을 경우 시간이 빠르고 정 반대의 경우 느리다.

 

public class insertion_sort {
	public static void main(String args[]) {
		int[] arr = {1,5,4,2,7};
		int i,j;
		for(i=1; i<arr.length; i++)
			for(j=i; arr[j]<arr[j-1]&&j>0; j--)
				swap(arr,j,j-1);
		for(i=0; i<arr.length; i++)
			System.out.print(arr[i]);
		
	}
	static void swap(int[] arr,int i,int j) {
		int temp;
		temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	

}

 

shell sort(셸정렬)


셸 정렬이란 주어진 데이터를 특정 매개변수 값의 길이를 갖는 부파일(subfile)로 쪼개서, 각 부파일에서 정렬을 수행한다. 부파일의 길이가 1이될 때까지 이 과정을 반복한다.

사용하는 이유는 삽입정렬에서 내림차순으로 정릴할 때 가장 작은 데이터가 끝에 있을 경우 많은 시간이 걸리는 것을 방지하기 위함이다.

 

※ 부파일로 이미 나눴기 때문에 최종적으로 부파일이 1이 되었을 때 대부분 정렬이 되어있다.

 

보통 부파일(h)의 길이는 h(1)=1 , h(i) = h(i-1)*3+1의 수열을 이용한다.

e.g. h1=1 h2 = 4 h3 = 13 ...

 

public class shell_sort {

	public static void main(String[] args) {
		int[] arr = {1,5,4,2,7,3,16,9};
		int i,j;
		int h=1;		
		while(true) {
			if(arr.length>h*3+1)
				h = h*3+1;
			else
				break;
		}
		while(h!=0) {
		for(i=h; i<arr.length; i++) {
			for(j=i; j-h>0&&arr[j]<arr[j-h]; j-=h)
				swap(arr,j,j-h);			
		} 
		h = h/3;
		}
		for(i=0; i<arr.length; i++)
			System.out.print(arr[i]);
	}
	static void swap(int []arr,int a,int b) {
		int temp;
		temp = arr[a];
		arr[a]=arr[b];
		arr[b]=temp;
	}
}

 

 

 

 

#자바 #정렬알고리즘 #선택정렬 #삽입정렬 #셸정렬

 

반응형
728x90
반응형

 

안녕하세요 이번 포스팅은 바로

"자료구조 중 큐(Queue)"

입니다

 

자료구조는 컴퓨터공학과처럼 코딩하는 전공을

진학하면 배우는 과목입니다.

지금 배우는 주제인 큐는 스택과 더불어 가장 기초적이면서도

다른 곳에서도 많이 쓰인다고 보시면됩니다.

이러한 큐를 두가지 방법으로 해보겠습니다.

하나는 직접 큐함수(add,delete)를 만들어보는 것이고

또 다른 하나는 기존에 있던 라이브러리를 통해

큐 함수(add,delete)를 써보는 것입니다.

 

 

큐(Queue)의 정의


한 쪽 끝에서만 삽입과 삭제가 이루어지는 스택과는 달리

한 쪽 끝에서는 삭제, 반대쪽 끝에서는 삽입만 가능한 순서화 리스트이다.

그리고 가장 먼저 삽입된 원소가 가장 먼저 삭제되는 형태인데 

이는 First in First out(FIFO)라 불린다.

 

삽입과 삭제가 이루어지는 함수 add와 delete가 존재하며

add는 rear의 위치에서 발생하고 delete는 front의 위치에서 발생한다.

이런 식으로 rear에서는 삽입이 이루어지고 front에서는 삭제가 이루어진다.

 

 

 

큐(Queue) 직접 구현 - JAVA


<변수선언>

	static int rear = -1;
	static int front = -1;	
	static int full;
	static Integer[] queue;

 

스택은 한 곳에서 삽입과 삭제가 이루어지기 때문에 top 하나만 선언해주었지만

큐의 경우는 삽입,삭제가 반대 쪽에서 이루어지므로 rear,front 두 가지 변수를 선언합니다.

이때 rear,front 둘 다 -1로 초기화를 해주는데 이는 아직 값이 없다는 가정을 하는 것입니다.

 

그리고 full은 스택이 가득찼는 지 확인하기 위해 사용을 해줍니다.

stack은 큐를 배열로 설정해줍니다.

 

 

<ADD>

	static void add(int num) {
		if(rear+1==full)
			System.out.println("queue full");
		else
			queue[++rear] = num;
	
	}

rear는 삽입이 일어나는 곳인데 rear+1이 full의 위치와 같다면 스택이 가득찼음을 의미합니다.

이유는 num을 삽입할 때 전위연산자를 쓰기 때문에 if문에서도 +1을 해준 후 비교를 해줍니다.

그리고 if문을 통해 같으면 "stack full" 출력해줍니다.

 

else일 경우 스택에 값을 넣어주는데 이때 먼저 rear의 값을 증가시킨 뒤 num을 넣습니다.

이는 앞서 초기화에서  rear를 -1로 했는 이유이기도 합니다.

 

 

스택의 크기를 4로 주어 설정했기 때문에 add 함수 호출이 5번이 되는 시점 부터는

계속 "stack full"이 지속적으로 출력되는 것을 볼 수 있습니다.

 

 

<DELETE>

	static void delete() {
		if(rear==front)
			System.out.println("queue empty");
		else
			System.out.println(queue[++front]);
	}

delete 역시 if문이 존재하는데 이때 if문은 rear와 front를 비교해줍니다.

rear와 front가 같은 위치에 있다는 것은 스택에 값이 없다는 것을 의미하고 "stack empty"를 출력해줍니다.

이 역시 초기에 rear = -1 front = -1을 해주어 스택에 값이 없다는 것을 의미해줍니다

 

 

 

스택과는 다르게 delete를 했을 때 먼저 들어간 3 부터 나오는 것을 볼 수 있습니다.

또한, add를 3번 호출했기 때문에 delete가 4번 호출될 때 부터 "queue empty"를 출력하는 모습을 볼 수 있습니다.

 

 

 

 

 

 

 

큐(queue) 직접구현 - 최종코드


import java.util.Scanner;
public class Queue {	
	static int rear = -1;
	static int front = -1;	
	static int full;
	static Integer[] queue;	
	public static void main(String args[]) {
		Scanner sc = new Scanner(System.in);
		full = sc.nextInt();
		queue = new Integer[full];		
			
	}
	static void add(int num) {
		if(rear+1==full) {
			System.out.println("queue full");
		}
		else
			queue[++rear] = num;	
	}
	static void delete() {
		if(rear==front)
			System.out.println("queue empty");
		else
			System.out.println(queue[++front]);
	}

}

scanner를 이용해 배열의 크기를 받았습니다.

 

 

끝으로


이상으로 자료구조에 있어 가장 기초적이라고 할 수 있는

큐에 대해 알아보고 직접 구현해 보았습니다.

이보다 더 좋은 코드가 많기 때문에 작성된 코드는

단순 참고용으로 보시면 될 거 같습니다.

궁금한 점이나 문제점이 있으시면 댓글 남겨주시면 감사하겠습니다.

이상으로 읽어주셔서 감사합니다!!

반응형
728x90
반응형

안녕하세요 이번 포스팅은 바로

"자료구조 중 스택"

입니다

 

자료구조는 컴퓨터공학과처럼 코딩하는 전공을

진학하면 배우는 과목입니다.

지금 배우는 주제인 스택은 가장 기초적이면서도

다른 곳에서도 많이 쓰인다고 보시면됩니다.

이러한 스택을 두가지 방법으로 해보겠습니다.

하나는 직접 스택함수(POP,PUSH)를 만들어보는 것이고

또 다른 하나는 기존에 있던 라이브러리를 통해

스택의 함수(POP,PUSH)를 써보는 것입니다.

 

스택(Stack)의 정의

 

 

스택은 삽입과 삭제가 "top"이라 불리는 한쪽 끝 지점에서

발생하는 순서화 리스트이다.

그리고 나중에 들어온 데이터가 먼저 나가는 형태인데

이는 Last In, First Out(LIFO)라 불린다.

POP,PUSH와 같은 두 가지 기본 연산이 존재한다.

POP의 경우 top에 있는 데이터를 삭제하고

PUSH의 경우 top위에 데이터를 삽입한다.

 

 

위의 그림처럼 스택은 top의 위치만 변경시키면서 삽입과 삭제가 일어난다.

 

 

 

 

스택(STACK) 직접 구현 - JAVA

<변수선언>

static int top = -1;
	static int full;
	static Integer[] stack;

스택에서 top의 초기값은 -1로 줍니다.

그 이유는 아래 pop,push에서 설명드리겠습니다.

full의 경우는 스택이 가득찼는 지 확인을 위해 선언해줍니다.

리스트가 아닌 배열로 스택을 구현합니다.

<pop>

static void pop() {
		if (top == -1)
			System.out.println("스택이비었습니다.");
		else 
			System.out.println(stack[top--]);		
	}

pop의 경우 top의 위치를 후위연산자를 이용합니다.

보시는 거처럼 top의 값을 빼 출력을 하고 그 다음에 top을 감소시킵니다.

top이 0을 가리키고 있을 때도 마찬가지이므로 top을 감소시키면 -1이 됩니다.

따라서 top의 초기값을 -1로 설정합니다.

또한, push없이 pop을 사용하거나 데이터가 없을 때 pop의 사용을 막기 위해

아래 보시는 거처럼 조건문을 통해 스택이 비었다고 설명해줍니다.

pop();
pop();
pop();
pop();

 

 

 

<push>

static void push(int num) {
		if (top == full-1)
			System.out.println("꽉찼습니다!");
		else 
			stack[++top] = num;
	}

push의 경우 값을 전위연사자를 이용합니다.

그 이유는 바로 삽입하거나 후위연산자를 이용할 경우 기존의 데이터를 덮고

새로운 데이터가 삽입되는 상황이 발생합니다.

그렇기 때문에 top을 증가시켜 기존의 데이터 보다 높은 위치에 삽입을 시킵니다.

push의 경우도 pop처럼 full의 도달했을 때 꽉찼음을 알려줍니다.

이때 top == full-1로 조건을 주었는데 이는 push가 전위연산자를 이용하기 때문에

전위연산자를 사용했을 때 배열의 경계를 넘지 않는 지 비교하기 위함입니다.

아래의 경우 배열의 크기를 5로 했기 때문에 5개 넘어서는 "꽉찼습니다"를 출력합니다.

 

push(10);
push(20);
push(30);
push(40);
push(50);
push(60);
push(70);
push(80);

 

 

 

 

 

스택(STACK) 직접 구현 - 최종코드

import java.util.Scanner;

public class Stack {
	static int top = -1;
	static int full;
	static Integer[] stack;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		full = sc.nextInt();
		stack = new Integer[full];		
		/*
		  push		
		  pop
		 */		
	}
	static void pop() {
		if (top == -1)
			System.out.print("스택이비었습니다.");
		else 
			System.out.println(stack[top--]);	
	}
	static void push(int num) {
		if (top == full-1)
			System.out.println("꽉찼습니다!");
		else 
			stack[++top] = num;
	}
}

 

scanner를 이용해 스택의 크기를 조절했습니다.

끝으로

이상으로 자료구조에 있어 가장 기초적이라고 할 수 있는

스택에 대해 알아보고 직접 구현해 보았습니다.

이보다 더 좋은 코드가 많기 때문에 작성된 코드는

단순 참고용으로 보시면 될 거 같습니다.

궁금한 점이나 문제점이 있으시면 댓글 남겨주시면 감사하겠습니다.

이상으로 읽어주셔서 감사합니다!!

 

반응형

+ Recent posts