위상정렬

  • 일의 선후관계를 유지하면서 그래프를 짜는 알고리즘
  • Degree (진입차수배열)을 만든다. 
    • 진입차수의 배열 값은 선행되는 작업의 갯수 
    • 진입차수배열 값이 0이면 선행되는 작업이 없다는 뜻
  • Queue를 만들어서 진입차수가 0인 노드를 넣는다.(선행되는작업이없는노드)

dgree

  1 2 3 4 5 6
1,6실행 0 1 2 2 1 0
2,5실행 0 0 1 1 0 0
4,3실행 0 0 0 0 0 0

즉, 일을 순서대로 지키면서 BFS를 돌리는 알고리즘이다.

 

#include <algorithm>
#include <queue>
#include <functional>
#include <vector>
#include <iostream>
using namespace std;
/*
6 6
1 4
5 4
4 3
2 5
2 3
6 2 
*/

int n, m, a, b, score;
int main()
{
	ios_base::sync_with_stdio(false);
	cin >> n >> m;
	
	
	vector<vector<int>>graph(n + 1, vector<int>(n + 1, 0)); 
	vector<int> degree(n + 1);
	queue<int> q;
	for (int i = 0; i < m; i++)
	{ 
		cin >> a >> b;
		graph[a][b] = 1;
		degree[b]++;
	}
	for (int i = 1; i <= n; i++)
	{
		if (degree[i] == 0)
			q.push(i);
	}
	while (!q.empty())
	{
		int now = q.front();
		q.pop();
		cout << now << " ";
		for (int i = 1; i <= n; i++)
		{
			if (graph[now][i] == 1)
			{
				degree[i]--;
				if (degree[i] == 0)
					q.push(i);
			}

		}
	}
	return 0;
}

 

 

'Algorithm > Algorithm_Lecture' 카테고리의 다른 글

[강의]80. 다익스트라 알고리즘  (0) 2020.10.04

투포인트 알고리즘

  • 이중 포문으로 O(N^2)이 아닌 1초안에 답이 나오게 하기 위한 알고리즘

 

 

 

예제)

풀이

  • STEP1)A배열, B배열, C배열(교집합배열)을 만든다.
  • STEP2)A배열 0번째, B배열 0번째 비교해서  (A[0] < B[0])이면 A 배열의 포인터를 +1 만큼 증가 시킨다. 즉 더 작은 값의 배열을 +1 증가 시킨다.
  • STEP2,3)A[1] == B[0] 이면 그 값을 C[0]에 넣고 C[cnt++]해준다. 또한, A배열, B배열 포인터를 +1 만큼 증가시킨다.
  • STEP4)누군가 하나의 배열이 끝나면 종료.

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;


int main()
{
	int n, m, i, p1 = 0, p2 = 0, p3 = 0;
	cin >> n;
	vector<int> a(n);
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}

	sort(a.begin(), a.end());
	cin >> m;
	vector<int> b(m), c(n + m);

	for (int i = 0; i <m; i++)
	{
		cin >> b[i];
	}

	sort(b.begin(), b.end());

	//2point
	while (p1 < n && p2 < m)
	{
		if (a[p1] == b[p2])
		{
			c[p3++] = a[p1++];
			p2++;
		}
		else if (a[p1] < b[p2])
			p1++;
		else
			p2++;

	}
	for (int i = 0; i < p3; i++)
		cout << c[i] << " " ;
	return 0;
}

 

www.acmicpc.net/problem/14888

 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, ��

www.acmicpc.net

 

문제해설

  • 숫자 사이사이에 연산자를 끼워넣는 느낌.
  • 그러기 위해서는 DFS로 구현
    • ex) 연산자가 1 0 1 0 이라고 가정하고 List에 두가지 경우 0, 2와 2, 0경우를 재귀로 돌린다.
    • 0, 2의 경우 3 [0] 4 [2] 5 -->0은 더하기, 2는 곱하기 max or min을 구한다.
    • 2, 0의 경우 3 [2] 4 [0] 5 --> "

C++ 코드

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int map[11];
int vi[4];
int ar[4];
int resmax = -1000000001, resmin = 1000000001, n;
vector<int> v;

void input()
{
   cin >> n;
   for (int i = 0; i < n; i++)
      cin >> map[i];
   for (int i = 0; i < 4; i++)
      cin >> ar[i];
}

void pro(int ct)
{
   if (ct == n - 1)
   {
      int S = map[0];
      for (int i = 0; i < v.size(); i++)
      {
         if (v[i] == 0)
            S += map[i + 1];
         else if (v[i] == 1)
            S -= map[i + 1];
         else if (v[i] == 2)
            S *= map[i + 1];
         else if (v[i] == 3)
            S /= map[i + 1];
      }
      resmax = max(resmax, S);
      resmin = min(resmin, S);
      return;
   }

   for (int w = 0; w < 4; w++)
   {
      if (ar[w] == 0)
         continue;
      if (vi[w] < ar[w])
      {
         vi[w]++;
         v.push_back(w);
         pro(ct + 1);
         v.pop_back();
         vi[w]--;
      }
   }
}

int main()
{
   input();
   pro(0);
   cout << resmax << endl << resmin << endl;
   return 0;
}

 

Java

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

public class Main {
	static int N;
	static int numbers[];
	static int count[] = new int[4];
	static int visited[];
	static ArrayList<Integer> comb = new ArrayList<Integer>();
	static int max = -1000000001;
	static int min = 1000000001;

	// static int result_max;
	// static int result_min;
	static void pro(int ct) {
		if (ct == N - 1) {
			// System.out.println(comb);
			int sum = numbers[0];
			for (int i = 0; i < comb.size(); i++) {
				if (comb.get(i) == 0) {
					sum += numbers[i + 1];
				} else if (comb.get(i) == 1) {
					sum -= numbers[i + 1];
				} else if (comb.get(i) == 2) {
					sum *= numbers[i + 1];
				} else if (comb.get(i) == 3) {
					sum /= numbers[i + 1];
				}
			}
			// System.out.println(sum);
			max = Math.max(sum, max);
			min = Math.min(sum, min);

		}
		for (int i = 0; i < 4; i++) {
			if (count[i] == 0)
				continue;
			if (visited[i] != count[i]) {
				visited[i]++;
				comb.add(i);
				pro(ct + 1);
				// System.out.println(comb);
				comb.remove(comb.size() - 1);
				visited[i]--;
			}
		}
	}

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		N = Integer.parseInt(br.readLine());
		numbers = new int[N];
		// 0: + 1:- 2: x 3: /
		visited = new int[4];
		Arrays.fill(visited, 0);
		String input = br.readLine();
		StringTokenizer st = new StringTokenizer(input);
		for (int i = 0; i < N; i++) {
			numbers[i] = Integer.parseInt(st.nextToken());
		}
		input = br.readLine();
		st = new StringTokenizer(input);
		for (int i = 0; i < 4; i++) {
			count[i] = Integer.parseInt(st.nextToken());
		}
		pro(0);
		System.out.println(max);
		System.out.println(min);
	}

}

www.acmicpc.net/problem/9536

 

9536번: 여우는 어떻게 울지?

각 테스트케이스마다 여우의 울음소리를 한 줄씩, 녹음된 순서대로 출력한다. 여우의 울음소리가 녹음되어 있음이 보장된다. (알려진 것과는 달리, 여우는 모스 부호로 의사소통하지 않는다.)

www.acmicpc.net

 

문제해설

  • 알고리즘 자체보다는 문자열 문제
  • what does the fox say? 가 나올 때 문자열을 종료시켜주는 것
  • StringToken 잘 쓰기. -->

wantairpod.tistory.com/86

 

[Java 입출력] StringTokenizer

StringTokenizer 클래스는 문자열을 우리가 지정한 구분자로 문자열을 쪼개주는 클래스입니다. 그렇게 쪼개어진 문자열을 우리는 토큰(token)이라고 부릅니다. java.util.StringTokenizer int countTokens() 남..

wantairpod.tistory.com

Java

package Z_ShinHanCard_Prepare;
import java.util.*;
import java.io.*;
/*
 * 1
toot woof wa ow ow ow pa blub blub pa toot pa blub pa pa ow pow toot
dog goes woof
fish goes blub
elephant goes toot
seal goes ow
what does the fox say?
 * */
public class D4백준9536_여우는어떻게울지 
{
	

	public static void main(String[] args) throws Exception
	{	String question="what does the fox say?";
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String input = br.readLine();
		int T = Integer.parseInt(input);
		String s[]= new String[T];
		Vector<String> animals = new Vector<String>();
		StringTokenizer st;
		for(int i = 0 ; i <T ; i++)
		{
			animals.clear();
			input = br.readLine();
			s[i]=input; //동물소리 입력받음
			for(int  j= 0 ; j<100 ; j++)
			{
				String temp =br.readLine();
				if(temp.equals(question))
				{
					break;
				}
				st =new StringTokenizer(temp," ");
				int tempCout =st.countTokens();
						
				for(int w= 0 ; w<st.countTokens() ;j++) {
					if(st.nextToken().equals("goes"))
					{
						animals.add(st.nextToken());
					}
				} 
			}
			
			st=new StringTokenizer(s[i]," "); 	
			while (st.hasMoreTokens()) 
			{
				int check=0;
				String animal = st.nextToken();
				
				for (int k=0; k<animals.size(); k++) 
				{
					if (animal.equals(animals.get(k)))
					{
						check=1;
						break;
					}
					else check=0;
				}
				if (check==0) {
					System.out.print(animal+ " ");
				}
			}
		} 
	}

}
  • StringTokenizer 클래스는 문자열을 우리가 지정한 구분자로 문자열을 쪼개주는 클래스입니다. 그렇게 쪼개어진 문자열을 우리는 토큰(token)이라고 부릅니다.
  • java.util.StringTokenizer
    • int countTokens()
      • 남아 있는 token 반환
    • boolean hasMoreElemets()
      • 다음 토큰이 있으면 true 없으면 false 반환
    • String nextToken()
      • 다음의 토큰을 반환
  • 코드
package Z_ShinHanCard_Prepare;
import java.util.*;
import java.io.*;
public class D4StringTokenizer연습 
{

	public static void main(String[] args) 
	{
		// TODO Auto-generated method stub
		//String totalStr ="toot woof wa ow ow ow pa blub blub pa toot pa blub pa pa ow pow toot";
		String totalStr ="hello world hi world";
		StringTokenizer st = new StringTokenizer(totalStr);
		System.out.println(st);
		System.out.println();
		
		
		System.out.println("total tokens : " + st.countTokens());
		System.out.println();
		
		while(st.hasMoreTokens())
		{
			System.out.println(st.nextToken());
		}
		
		System.out.println("total tokens : " + st.countTokens());
		
		
	}

}

 

결과

CASE1

  • 붙어있는 경우

  • N 첫줄을 parse해준다.
  • N을 이용해서 루프를 돈다.
  • i는 한줄씩->input=br.readLine();
  • j는 한글자씩-> arr[i][j] = input.charAt(j) - '0';
    • br.readLine()은 한줄을 String으로 받기 때문에 숫자로 바꿔주기 위해서 -'0'을 해준다.
		BufferedReader br= new BufferedReader (new InputStreamReader(System.in));
		String input= br.readLine();
		N = Integer.parseInt(input);
		house = new int [N][N];
		visited = new boolean [N][N];
		//Arrays.fill(visited, false);
		for(int i = 0 ; i < N; i++)
		{
			input = br.readLine();
			for(int j =0 ; j < N ; j++)
			{
				int tempNum = input.charAt(j);
				house[i][j] = input.charAt(j) -'0'; 
			}
		}

 

CASE2

  • 떨어져 있는 경우

  • StringTokenizer 를 사용한다. 
  • br.readLine(=String) 은 같다. 하지만 한 줄에서 띄어쓰기전까지만 짜른다.
  • ex) 30 50
    • StringTokenizer st =new StringTokeizer(input); //input은 한 줄 
    • int first = Interger.parseInt(st.nextToken()); // 한줄에서 띄어쓰기 전까지 first -> 30
    • int second = Integer.parseInt(st.nextToken()); // 50
		BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
		int T = Integer.parseInt(br.readLine());
		for(int tc =0; tc<T; tc++)
		{
			inin();
			L=Integer.parseInt(br.readLine()); //L*L 
			visit =new boolean[L][L];
			for (boolean row[]: visit) {
				Arrays.fill(row,  false);
			} //초기화시킴
			String input = br.readLine();  // 0,0
			StringTokenizer st= new StringTokenizer(input);

			int sx =Integer.parseInt(st.nextToken()); 
			int sy =Integer.parseInt(st.nextToken()); 
			input = br.readLine();  // 0,0
			st= new StringTokenizer(input);
			int ex =Integer.parseInt(st.nextToken());
			int ey =Integer.parseInt(st.nextToken());
         }

www.acmicpc.net/problem/1654

 

1654번: 랜선 자르기

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그

www.acmicpc.net

 

문제풀이

  • 이분 탐색으로 구현
  • 정확하게 이분탐색을 알아야만 풀 수있음
  • int형이아닌 long으로 받는 것이 중요 (N=1,000,000)
  • 길이는 자연수라고 했으므로 min 값을 1로 잡는 것이 중요(상식적으로 길이가 0인 선은 없는 것임)
min min middle
1 802 401
1 400 200
201 400 300
299 201 250
201 249 225
201 224 212
201 211 206
201 205 203
201 202 201
201 200 201

 

Java

package Z_ShinHanCard_Prepare;
/*
 * 4 11
   802
   743
   457
   539
 * */
import java.io.*;
import java.util.*;
public class D3백준_랜선짜르기_이분탐색 {
	static ArrayList<Integer> arr  = new ArrayList<Integer>();
	public static void main(String[] args) throws Exception
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String input = br.readLine();
		StringTokenizer st = new StringTokenizer(input);
		int R = Integer.parseInt(st.nextToken());
		int C = Integer.parseInt(st.nextToken());
		for(int i =0 ; i <R ; i++)
		{
			input = br.readLine();
			int temp = Integer.parseInt(input); 
			arr.add(temp);
		}
		Collections.sort(arr);
		//arr : 457 539 743 802 
		long max = arr.get(R-1); 
		long min = 1; //자연수라서 1
		long middle =0; 
		
		while(max>=min) //이분탐색
		{
			middle = (max+min)/ 2;
			long allcount =0;
			for(int i =0  ; i <arr.size(); i++)
			{
				allcount += arr.get(i) / middle; 
			}
			 
			if(allcount >= C) 
			{
				min = middle +1;
			}else if(allcount <C )
			{
				max=middle -1;
			}
				
		}
		
		System.out.println(max);
		 
		
		// TODO Auto-generated method stub

	}

}

www.acmicpc.net/problem/9012

 

9012번: 괄호

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고

www.acmicpc.net

 

문제풀이

  • '('은 Stack에 계속 담음
  • ')'은 Stack에 '('로 끝날때 '(' 을 pop 시켜준다.
    • 만약 Stack 비어있으면 break

Java

package Z_ShinHanCard_Prepare;
/*
 *  6
	(())())
	(((()())()
	(()())((()))
	((()()(()))(((())))()
	()()()()(()()())()
	(()((())()(
*/
import java.io.BufferedReader;

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

public class D3백준9012_괄호_stack {
	static int T,n,m;
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int T= Integer.parseInt(br.readLine());
		Stack<Character> stack = new Stack<Character>();
		boolean check = true;
		for(int i = 0 ; i < T ; i++)
		{
			String input = br.readLine();
			stack.clear();
			for(int j = 0 ; j < input.length() ; j++)
			{
				check =true;
				char temp = input.charAt(j);
				if(temp == '(')
				{
					stack.push(temp);
				}else if(temp ==')')
				{
					if(stack.isEmpty())
					{
						check = false;
						break;
					}
					stack.pop();
					
				}
				 
			}
			if(check ==true && stack.isEmpty())
				System.out.println("YES");
			else
				System.out.println("NO");
			
 		}
	}
}

 

+ Recent posts