본문 바로가기

Archived(CSE Programming)/알고리즘(C++)

다이나믹 프로그래밍 문제 2

1. 가장 긴 증가하는 부분 수열(LIS)

문제 : https://www.acmicpc.net/problem/11053

 

11053번: 가장 긴 증가하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.

www.acmicpc.net

풀이

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
	int n, max = 1;
	cin >> n;

	vector<int> d(n + 1, 1); 
	vector<int> a(n + 1, 0);

	for (int i = 1; i <= n; i++)
		cin >> a[i];
	
	for (int i = 2; i <= n; i++) {
		for (int j = 1; j < i; j++) {
			// 현재 값보다 작고 새로운 수열을 만들 수 있을 경우
			if (a[i] > a[j] && d[i] <= d[j])
				d[i] = d[j] + 1;

			if (d[max] < d[i])
				max = i;
		}
	}


	cout << d[max];
}

2. 가장 긴 증가하는 부분수열 4(LIS)

문제 : https://www.acmicpc.net/problem/14002

 

14002번: 가장 긴 증가하는 부분 수열 4

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.

www.acmicpc.net

풀이

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void print_v(int);
vector<int> v;
vector<int> a;

int main() {
	int n, max = 1;
	cin >> n;

	vector<int> d(n + 1, 1);
	v.assign(n + 1, 0);
	a.assign(n + 1, 0);

	for (int i = 1; i <= n; i++)
		cin >> a[i];

	for (int i = 2; i <= n; i++) {
		for (int j = 1; j < i; j++) {
			// 현재 값보다 작고 새로운 수열을 만들 수 있을 경우
			if (a[i] > a[j] && d[i] <= d[j]) {
				d[i] = d[j] + 1;
				v[i] = j;
			}
			if (d[max] < d[i])
				max = i;
		}
	}
	cout << d[max] << endl;
	print_v(max);
}

void print_v(int idx) {
	if (idx == 0) 
		return;

	print_v(v[idx]);
	cout << a[idx] << " ";
}

3. 가장 긴 감소하는 부분수열(LDS)

문제 : https://www.acmicpc.net/problem/11722

 

11722번: 가장 긴 감소하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 감소하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 30, 10, 20, 20, 10} 인 경우에 가장 긴 감소하는 부분 수열은 A = {10, 30, 10, 20, 20, 10}  이고, 길이는 3이다.

www.acmicpc.net

풀이

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
	int n, max = 1;
	cin >> n;

	vector<int> d(n + 1, 1);
	vector<int> a(n + 1, 0);

	for (int i = 1; i <= n; i++)
		cin >> a[i];

	for (int i = 2; i <= n; i++) {
		for (int j = 1; j < i; j++) {
			// 현재 값보다 크고 새로운 수열을 만들 수 있을 경우
			if (a[i] < a[j] && d[i] <= d[j])
				d[i] = d[j] + 1;

			if (d[max] < d[i])
				max = i;
		}
	}


	cout << d[max];
}

4. 가장 긴 바이토닉 수열

문제 : https://www.acmicpc.net/problem/11054

 

11054번: 가장 긴 바이토닉 부분 수열

첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)

www.acmicpc.net

풀이

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
	int n, max = 1;
	cin >> n;

	vector<int> d(n + 1, 1);
	vector<int> d2(n + 1, 1);
	vector<int> a(n + 1, 0);

	for (int i = 1; i <= n; i++)
		cin >> a[i];

	for (int i = 2; i <= n; i++) {
		for (int j = 1; j < i; j++) {
			// 증가 수열
			// 현재 값보다 작고 새로운 수열을 만들 수 있을 경우
			if (a[i] > a[j] && d[i] <= d[j])
				d[i] = d[j] + 1;
		}
	}
	for (int i = n-1; i >= 1; i--) {
		for (int j = n; j > i; j--) {
			// 뒤에서부터 증가 수열
			// 현재 값보다 작고 새로운 수열을 만들 수 있을 경우
			if (a[i] > a[j] && d2[i] <= d2[j])
				d2[i] = d2[j] + 1;
		}
	}

	// 최대 바이토닉 수열 찾기
	for (int i = 1; i <= n; i++)
		if (d[max] + d2[max] - 1 < d[i] + d2[i] - 1)
			max = i;

	cout << d[max] + d2[max] - 1;
}

5. 연속합

문제 : https://www.acmicpc.net/problem/1912

 

1912번: 연속합

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

풀이

#include <iostream>
#include <vector>
using namespace std;

int main() {
	int n, max=1;
	cin >> n;

	vector<int> d(n + 1);
	vector<int> a(n + 1);

	for (int i = 1; i <= n; i++)
		cin >> a[i];

	d[1] = a[1];
	for (int i = 2; i <= n; i++) {
		// 다시시작이 더 크면
		if (a[i] > a[i] + d[i - 1])
			d[i] = a[i];
		// 아니면
		else
			d[i] = d[i - 1] + a[i];

		if (d[max] < d[i])
			max = i;
	}

	cout << d[max];
}

6. 제곱수의 합

문제 : https://www.acmicpc.net/problem/1699

 

1699번: 제곱수의 합

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다. 이 경우, 수학자 숌크라테스는 “11은 3개 항의 제곱수 합으로 표현할 수 있다.”라고 말한다. 또한 11은 그보다 적은 항의 제곱수 합으로 표현할 수 없으므로, 11을 그 합으로써 표현할 수 있는 제곱수 항의 최소 개수는

www.acmicpc.net

풀이

#include <iostream>
#include <vector>
#define MAX 99999999
using namespace std;

int main() {
	int n;
	cin >> n;

	vector<int> d(n + 1, MAX);
	d[0] = 0, d[1] = 1; // 초기화
	// 2~n까지 DP
	for (int i = 2; i <= n; i++) {
		for (int j = 1; j*j <= n; j++) {
			// 해당 값이 존재하고 더 작은 수로 만들 수 있으면
			if (i - (j*j) >= 0 && d[i - (j*j)] < d[i])
				d[i] = d[i - (j*j)] + 1;
		}
	}
	cout << d[n];
}

'Archived(CSE Programming) > 알고리즘(C++)' 카테고리의 다른 글

브루트포스_연습2  (0) 2019.09.26
브루트포스_연습  (0) 2019.09.01
다이나믹 프로그래밍 문제  (0) 2019.08.25
다이나믹 프로그래밍(Dynamic Programming)  (0) 2019.08.22
그래프의 심화  (0) 2019.08.16