[Java]알고리즘 기초

박진우·2022년 10월 31일
0

알고리즘 기초

목록 보기
23/29

11723 집합

문제

비어있는 공집합 S가 주어졌을 때, 아래 연산을 수행하는 프로그램을 작성하시오.

add x: S에 x를 추가한다. (1 ≤ x ≤ 20) S에 x가 이미 있는 경우에는 연산을 무시한다.
remove x: S에서 x를 제거한다. (1 ≤ x ≤ 20) S에 x가 없는 경우에는 연산을 무시한다.
check x: S에 x가 있으면 1을, 없으면 0을 출력한다. (1 ≤ x ≤ 20)
toggle x: S에 x가 있으면 x를 제거하고, 없으면 x를 추가한다. (1 ≤ x ≤ 20)
all: S를 {1, 2, ..., 20} 으로 바꾼다.
empty: S를 공집합으로 바꾼다.

입력

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다.

둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

출력

check 연산이 주어질때마다, 결과를 출력한다.

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class B11723 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		int M = sc.nextInt();
		Set<Integer> set = new HashSet<Integer>();
		for(int i = 0;i<M;i++) {
			String S = sc.next();
			int x = 0;
			switch(S){
			case "add":
				x = sc.nextInt();
				set.add(x);
				break;
			case "remove":
				x = sc.nextInt();
				set.remove(x);
				break;
			case "check":
				x = sc.nextInt();
				if(set.contains(x)) {
					sb.append("1\n");
				}else {
					sb.append("0\n");
				}
				break;
			case "toggle":
				x = sc.nextInt();
				if(set.contains(x)) {
					set.remove(x);
				}else {
					set.add(x);
				}
				break;
			case "all":
				for(int k = 0;k<20;k++) {
					set.add(k+1);
				}
				break;
			case "empty":
				set.clear();
				break;
			}
		}
		System.out.println(sb);
	}
}

1182 부분수열의 합

문제

N개의 정수로 이루어진 수열이 있을 때, 크기가 양수인 부분수열 중에서 그 수열의 원소를 다 더한 값이 S가 되는 경우의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.

출력

첫째 줄에 합이 S가 되는 부분수열의 개수를 출력한다.

import java.util.Scanner;

public class B1182 {
	public static int N,M,ans =0;
	public static int arr[];
	public static boolean V[];
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		M = sc.nextInt();
		arr = new int[N];
		for(int i = 0;i<N;i++) {
			arr[i] = sc.nextInt();
		}
		dfs(0,0);
		System.out.println(ans);
	}
	
	public static void dfs(int D,int sum) {
		if(N == D) {
			return;
			}
		else if(sum+arr[D] == M){
				ans++;
			}
		dfs(D+1,sum);
		dfs(D+1,sum+arr[D]);
		}
	}


14889 스타트와 링크

문제

오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.

BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.

N=4이고, S가 아래와 같은 경우를 살펴보자.

i\j	1	2	3	4
1	 	1	2	3
2	4	 	5	6
3	7	1	 	2
4	3	4	5	 

예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.

스타트 팀: S12 + S21 = 1 + 4 = 5
링크 팀: S34 + S43 = 2 + 5 = 7
1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.

스타트 팀: S13 + S31 = 2 + 7 = 9
링크 팀: S24 + S42 = 6 + 4 = 10
축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.

입력

첫째 줄에 N(4 ≤ N ≤ 20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij 이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class B14889 {
	public static int[][]map;
	public static int N;
	public static boolean V[];
	public static int ans = Integer.MAX_VALUE;
	
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		N = Integer.parseInt(br.readLine());
		map = new int[N][N];
		V = new boolean[N];
		for(int i = 0;i<N;i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			for(int j = 0;j<N;j++) {
				map[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		dfs(0,0);
		System.out.println(ans);
	}
	
	public static void dfs(int at,int D) {
		if(D == N/2) {
			diff();
			return;
		}
		for(int i = at;i<N;i++) {
			if(!V[i]) {
				V[i]= true;
				dfs(i+1,D+1);
				V[i] = false;
			}
		}
	}
	public static int diff() {
		int start = 0;
		int link = 0;
		for(int i = 0;i<N-1;i++) {
			for(int j = i+1;j<N;j++) {
				if(V[i] && V[j]) {
					start+=(map[i][j] + map[j][i]);
				}else if(!V[i] && !V[j]) {
					link +=(map[i][j] + map[j][i]);
				}
			}
		}
		int result = Math.abs(start-link);
		if(result == 0) {
			System.out.println(0);
			System.exit(0);
		}
		return ans = Math.min(result, ans);
	}
}

14391 종이조각

문제

영선이는 숫자가 쓰여 있는 직사각형 종이를 가지고 있다. 종이는 1×1 크기의 정사각형 칸으로 나누어져 있고, 숫자는 각 칸에 하나씩 쓰여 있다. 행은 위에서부터 아래까지 번호가 매겨져 있고, 열은 왼쪽부터 오른쪽까지 번호가 매겨져 있다.

영선이는 직사각형을 겹치지 않는 조각으로 자르려고 한다. 각 조각은 크기가 세로나 가로 크기가 1인 직사각형 모양이다. 길이가 N인 조각은 N자리 수로 나타낼 수 있다. 가로 조각은 왼쪽부터 오른쪽까지 수를 이어 붙인 것이고, 세로 조각은 위에서부터 아래까지 수를 이어붙인 것이다.

아래 그림은 4×4 크기의 종이를 자른 한 가지 방법이다.

각 조각의 합은 493 + 7160 + 23 + 58 + 9 + 45 + 91 = 7879 이다.

종이를 적절히 잘라서 조각의 합을 최대로 하는 프로그램을 작성하시오.

입력

첫째 줄에 종이 조각의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 4)

둘째 줄부터 종이 조각이 주어진다. 각 칸에 쓰여 있는 숫자는 0부터 9까지 중 하나이다.

출력

영선이가 얻을 수 있는 점수의 최댓값을 출력한다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class B14391 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		int M = Integer.parseInt(st.nextToken());
		int map[][] = new int[N][M];
		for(int i = 0;i<N;i++) {
			String S = br.readLine();
			for(int j = 0;j<M;j++) {
				map[i][j] = S.charAt(j)-'0';
			}
		}
		int ans = 0;
		for(int s = 0;s<(1<<(N*M));s++) {
			int sum = 0;
			for(int i = 0;i<N;i++) {
				int cur = 0;
				for(int j = 0;j<M;j++) {
					int k = i*M+j;
					if((s&(1<<k)) ==0) {
						cur*=10;
						cur+=map[i][j];
					}else {
						sum+=cur;
						cur = 0;
					}
				}
				sum+=cur;
			}
			for(int j = 0;j<M;j++) {
				int cur = 0;
				for(int i = 0;i<N;i++) {
					int k = i*M+j;
					if((s&(1<<k)) !=0) {
						cur*=10;
						cur+=map[i][j];
					}else {
						sum+=cur;
						cur = 0;
					}
				}
				sum+=cur;
			}
			
			ans = Math.max(ans, sum);
		}
		
				System.out.println(ans);
	}
	
	
			
}
profile
개발자를 꿈꾸는 사람입니다

0개의 댓글