728x90
 

1037번: 약수

첫째 줄에 N의 진짜 약수의 개수가 주어진다. 이 개수는 50보다 작거나 같은 자연수이다. 둘째 줄에는 N의 진짜 약수가 주어진다. 1,000,000보다 작거나 같고, 2보다 크거나 같은 자연수이고, 중복되지 않는다.

www.acmicpc.net

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

int main() {
	int n;
	cin >> n;
	vector<int> v(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i];
	}
	sort(v.begin(), v.end());
	cout << v[0] * v[v.size() - 1];
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1977번 완전제곱수  (0) 2020.02.07
[백준] 2163번 초콜릿 자르기  (0) 2020.02.07
[백준] 1094번 막대기  (0) 2020.02.07
[백준] 1010번 다리 놓기  (0) 2020.02.07
[백준] 1026번 보물  (0) 2020.02.07
728x90
 

1094번: 막대기

지민이는 길이가 64cm인 막대를 가지고 있다. 어느 날, 그는 길이가 Xcm인 막대가 가지고 싶어졌다. 지민이는 원래 가지고 있던 막대를 더 작은 막대로 자른다음에, 풀로 붙여서 길이가 Xcm인 막대를 만들려고 한다. 막대를 자르는 가장 쉬운 방법은 절반으로 자르는 것이다. 지민이는 아래와 같은 과정을 거쳐서 막대를 자르려고 한다. 지민이가 가지고 있는 막대의 길이를 모두 더한다. 처음에는 64cm 막대 하나만 가지고 있다. 이때, 합이 X보다 크다면,

www.acmicpc.net

#include <iostream>
using namespace std;

int main() {
	int n;
	cin >> n;
	int count = 0;
	while (n != 0) {
		if (n == 64) {
			n -= 64;
		}
		else if (n >= 32) {
			n -= 32;
		}
		else if (n >= 16) {
			n -= 16;
		}
		else if (n >= 8) {
			n -= 8;
		}
		else if (n >= 4) {
			n -= 4;
		}
		else if (n >= 2) {
			n -= 2;
		}
		else if (n >= 1) {
			n -= 1;
		}
		count++;
	}
	cout << count;
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 2163번 초콜릿 자르기  (0) 2020.02.07
[백준] 1037번 약수  (0) 2020.02.07
[백준] 1010번 다리 놓기  (0) 2020.02.07
[백준] 1026번 보물  (0) 2020.02.07
[백준] 4963번 섬의 개수  (0) 2020.02.06
728x90
 

1010번: 다리 놓기

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 강의 서쪽과 동쪽에 있는 사이트의 개수 정수 N, M (0 < N ≤ M < 30)이 주어진다.

www.acmicpc.net

서쪽에 있는 사이트의 개수 n, 동쪽에 있는 사이트의 개수 m이 입력으로 주어지면 mCn을 구하면 된다.

간단한 조합(Combination) 문제이다. 그런데 문제는 nCr은 n!/r!(n-r)!이기 때문에 분자를 분모로 나누기 전의 숫자는 너무 커질 수도 있다. 따라서 nCr과 nCn-r은 같다는 성질을 이용하면 된다.

10C2나 10C8은 같다. 10C8보다는 10C2를 하는 것이 훨씬 효율적이다.

따라서 처음에 입력을 받고 r = min(r, n - r);로 r을 줄여주었다.

#include <iostream>
using namespace std;

int main() {
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int t;
	cin >> t;
	for (int i = 0; i < t; i++) {
		int r, n;
		cin >> r >> n;
		r = min(r, n - r);
		long long numerator = 1;
		long long denominator = 1;
		for (int i = n; i > n - r; i--) {
			numerator *= i;
		}
		for (int i = r; i >= 1; i--) {
			denominator *= i;
		}
		cout << numerator / denominator << '\n';
	}
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1037번 약수  (0) 2020.02.07
[백준] 1094번 막대기  (0) 2020.02.07
[백준] 1026번 보물  (0) 2020.02.07
[백준] 4963번 섬의 개수  (0) 2020.02.06
[백준] 1912번 연속합  (0) 2020.02.06
728x90
 

1026번: 보물

첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거나 같은 음이 아닌 정수이다.

www.acmicpc.net

B는 재배열하면 안 된다고 써있지만 A를 자유롭게 재배열하면 B를 재배열하는 것과 같기 때문에 B를 재배열해도 상관없다.

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

bool cmp(int x, int y) {
	return x > y;
}

int main() {
	int n;
	cin >> n;
	vector<int> a(n);
	vector<int> b(n);
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	for (int i = 0; i < n; i++) {
		cin >> b[i];
	}
	sort(a.begin(), a.end());
	sort(b.begin(), b.end(), cmp);
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += (a[i] * b[i]);
	}
	cout << sum;
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1094번 막대기  (0) 2020.02.07
[백준] 1010번 다리 놓기  (0) 2020.02.07
[백준] 4963번 섬의 개수  (0) 2020.02.06
[백준] 1912번 연속합  (0) 2020.02.06
[백준] 2656번 전깃줄  (0) 2020.02.06
728x90

만약에 입력으로 n을 입력받아 크기가 n인 배열을 만들고 싶다면 어떻게 해야 할까?

int n;
cin >> n;
int arr[n];

이렇게 하면 될까?

이렇게 선언하면 컴파일 에러가 나는 것을 볼 수 있다.

배열의 크기를 나타내는 [] 안에는 const로 선언된 상수 변수 또는 리터럴 상수만 들어갈 수 있다.

따라서 이 경우 포인터를 이용한 동적할당을 해야 한다.

이렇게 동적 할당을 해주면 에러가 안 나고 크기가 n인 int 배열이 잘 선언되었다.

 

하지만 배열의 크기를 미리 알지 못 할수도 있다.

입력이 계속 들어오고 입력이 0일 경우 입력을 그만 받는 프로그램이 있을 수도 있다.

 

이 경우 배열의 크기를 얼마로 잡아야 할까?

물론 int arr[100000]; 이렇게 크게 잡아놓고 입력을 받을 수도 있지만 메모리 공간을 너무 낭비한다는 단점이 있고 

입력으로 들어온 수의 개수를 초과하는 인덱스에 접근해도 IndexOutOfRange예외가 발생하지 않기 때문에 쓰레기값을 가지고 엉뚱한 계산을 할 수도 있다.

 

배열의 이러한 한계를 극복한 것이 vector 클래스이다. 벡터는 사용하다가 크기가 부족해도 크기를 늘릴 수도 있고 초기에 크기를 선언하지 않아도 되기 때문에 배열보다 훨씬 유연하다. 그리고 벡터는 배열과 다르게 클래스이기 때문에 유용한 함수들도 들어있어서 더욱 편하다.

http://www.cplusplus.com/reference/vector/vector/

 

vector - C++ Reference

difference_typea signed integral type, identical to: iterator_traits ::difference_type usually the same as ptrdiff_t

www.cplusplus.com

 

벡터의 선언 방법은 다음과 같다.

#include <vector>

일단 <vector> 헤더파일을 포함시켜주고

vector<int> v;

이렇게 선언한다. 그러면 v라는 빈 벡터가 생성된다.

벡터는 vector<T> 이렇게 만들어진 템플릿 클래스이기 때문에 벡터에 들어갈 타입을 <>이 사에에 적어줘야 한다.

 

이렇게 선언한 벡터 v에 1이라는 정수를 집어넣고 싶다면?

v.push_back(1);

이렇게 하면 된다.

 

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

int main() {
	vector<int> v;
	v.push_back(1);
	v.push_back(7);
	v.push_back(15);
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
	return 0;
}

이 코드의 실행 결과는 다음과 같다.

벡터의 모든 원소를 for문을 돌리면서 출력하는데 v.size()를 사용했다.

v.size()를 하면 벡터에 있는 원소의 개수를 반환한다. 지금 이 코드의 경우 v.size()를 하면 3을 반환한다.

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

int main() {
	vector<int> v;
	v.push_back(1);
	v.push_back(7);
	v.push_back(15);
	cout << "벡터의 크기: " << v.size() << endl;
	return 0;
}

위 코드의 실행 결과

지금 우리가 벡터를 사용한 방법은 빈 벡터를 선언하고 push_back() 함수를 사용하여 값을 넣어주었다.

하지만 벡터의 크기를 처음부터 잡고 싶을 때엔 어떻게 해야 할까?

vector<int> v(3);

이렇게 선언하면 크기가 3인 벡터가 생성된다.

그럼 이렇게 크기가 3인 벡터를 선언하고 아까와 같이 push_back 함수를 통해 1, 7, 15를 벡터에 넣으면 어떻게 될까?

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

int main() {
	vector<int> v(3);
	v.push_back(1);
	v.push_back(7);
	v.push_back(15);
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
	return 0;
}

위 코드의 실행 결과

크기가 3인 벡터를 선언하고 push_back()으로 원소를 넣으면 이렇게 뒤에 원소가 추가되는 것을 볼 수 있다.

즉 push_back() 함수를 호출하면 반드시 벡터의 크기가 늘어난다는 것을 알 수 있다.

그리고 벡터의 크기를 정해서 선언하면 초기값 0으로 채워진 벡터가 생성된다는 것도 알 수 있다.

 

따라서 이렇게 일정 크기의 벡터를 선언하면 push_back()이 아니라

v[0] = 1;
v[1] = 7;
v[2] = 15;

이렇게 인덱스로 접근할 수 있다.

 

그러면 초기값을 0이 아니라 5로 주고 싶으면 어떻게 해야 할까?

vector<int> v(3, 5); //모든 원소가 5인 크기가 3인 벡터 생성.

이렇게 선언하면 초기값 5로 채워진 크기가 3인 벡터가 생성된다.

 

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

int main() {
	vector<int> v(3, 5);
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
	return 0;
}

위 코드의 실행 결과

이 코드를 실행하면 이렇게 5로 초기화되어 있는 것을 볼 수 있다.

 

또 내가 원하는 초기값이 다 다르다면 이렇게도 가능하다.

vector<int> v = {1, 7, 15};
#include <iostream>
#include <vector>
using namespace std;

int main() {
	vector<int> v = { 1, 7, 15 };
	cout << "벡터의 크기: " << v.size() << endl;
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
	return 0;
}

위 코드의 실행 결과

 

벡터 클래스의 대표적인 생성자를 다시 살펴보자면

+vector() T 타입의 빈 벡터 생성
+vector(size: int) 숫자의 경우 0으로, bool의 경우 false로 초기화된 size 크기의 벡터 생성
+vector(size: int, defaultValue: T) defaultValue로 초기화된 size 크기의 벡터 생성

자주 쓰이는 대표적인 생성자는 이렇게 3개가 있다.

 

그러면 이제 vector 클래스의 유용한 함수들을 살펴보자.

+push_back(element: T): void 벡터에 element를 원소로 추가
+pop_back(): void 벡터의 마지막 원소를 삭제
+size(): unsigned int const 벡터의 크기(원소 개수) 반환
+at(index: int): T const index 위치에 있는 원소 반환. v[index]로 접근하는 것과 같다.
+empty(): bool const 벡터의 크기가 0인지 아닌지 반환
+clear(): void 벡터의 모든 원소를 삭제
+swap(v2: vector): void 벡터의 내용을 다른 벡터 v2와 교환. 같은 타입의 벡터만 가능
+erase(iterator position): iterator position 위치에 있는 원소를 삭제
#include <iostream>
#include <vector>
using namespace std;

int main() {
	vector<int> v;
	cout << "벡터의 크기: " << v.size() << endl;
	cout << "벡터가 비어있나요? " << (v.empty() ? "true" : "false") << endl;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	cout << "벡터가 비어있나요? " << (v.empty() ? "true" : "false") << endl;
	cout << "벡터의 크기: " << v.size() << endl;
	cout << "0번째 원소: " << v[0] << endl; //이렇게 []로도 접근 가능하고
	cout << "3번째 원소: " << v.at(3) << endl; //이렇게 at() 함수로도 인덱스에 접근 가능
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << " ";
	}
	cout << endl;
	v.pop_back();
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << " "; //마지막 원소였던 5가 삭제된 것을 볼 수 있음
	}
	cout << endl;
	v.clear(); //벡터의 모든 원소 삭제
	cout << "벡터의 크기: " << v.size() << endl;
	cout << "벡터가 비어있나요? " << (v.empty() ? "true" : "false") << endl;
	cout << endl;
	return 0;
}

위 코드의 실행 결과

이 코드와 실행 결과만 보면 함수 사용법은 쉽게 알 수 있으리라 생각된다.

 

erase 함수 사용법은 조금 어려울 수도 있기 때문에 따로 빼서 설명하자면 예를 들어 i번째 원소를 벡터에서 삭제하고 싶다면 다음과 같이 쓰면 된다.

v.erase(v.begin() + i);

이렇게 하면 된다. erase 함수의 인자는 인덱스가 아니라 주소이기 때문에 저렇게 써야 한다. v.begin()은 벡터 v의 시작 주소이다.

전체 코드로 실습을 해보자면

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

int main() {
	vector<int> v(10);
	for (int i = 0; i < 10; i++) {
		v[i] = i;
	}
	cout << "지우기 전:          ";
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << " ";
	}
	cout << endl;
	v.erase(v.begin() + 5);
	cout << "5번 인덱스 지운 후: ";
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << " ";
	}
	cout << endl;
	return 0;
}

위 코드의 실행 결과

v.erase(v.begin() + 5);로 5번 인덱스에 있는 원소가 삭제된 것을 볼 수 있다.

 

그러면 이차원 배열이 필요하면 어떻게 해야 할까?

벡터의 벡터로 이차원 배열을 구현할 수 있다. 5행 3열짜리 이차원 배열을 선언하고 싶다면 다음과 같이 하면 된다.

vector<vector<int>> v(5);
for (int i = 0; i < 5; i++) {
	v[i] = vector<int>(3);
}

코드를 보면 크기가 5인 벡터를 선언하는데 벡터의 원소로 벡터를 가지는 벡터이다.

즉, 빈 벡터 5개를 원소로 가지는 벡터이다.

그러고 나서 for문을 돌면서 각각의 빈 벡터를 크기가 3인 벡터로 할당해준다.

그러면 5x3짜리 이차원 배열과 같은 벡터가 만들어진다.

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

int main() {
	vector<vector<int>> v(5);
	for (int i = 0; i < 5; i++) {
		v[i] = vector<int>(3);
	}
	for (int i = 0; i < v.size(); i++) {
		for (int j = 0; j < v[i].size(); j++) {
			cout << v[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}

위 코드의 실행 결과

이 코드를 줄여서 한 줄에 처리하고 싶다면

vector<vector<int>> w(5, vector<int>(3));

이렇게 하면 된다.

728x90
728x90
 

4963번: 섬의 개수

문제 정사각형으로 이루어져 있는 섬과 바다 지도가 주어진다. 섬의 개수를 세는 프로그램을 작성하시오. 한 정사각형과 가로, 세로 또는 대각선으로 연결되어 있는 사각형은 걸어갈 수 있는 사각형이다.  두 정사각형이 같은 섬에 있으려면, 한 정사각형에서 다른 정사각형으로 걸어서 갈 수 있는 경로가 있어야 한다. 지도는 바다로 둘러쌓여 있으며, 지도 밖으로 나갈 수 없다. 입력 입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는

www.acmicpc.net

왼쪽 오른쪽 위 아래 뿐만 아니라 대각선까지 되는 DFS, BFS 문제는 처음 봤다. 하지만 푸는 방법은 똑같으니 쉽게 풀 수 있었다.

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

int main() {
	while (true) {
		int w, h;
		cin >> w >> h;
		if (w == 0 && h == 0) break;
		vector<vector<int>> v(h);
		vector<vector<bool>> visited(h);
		for (int i = 0; i < h; i++) {
			v[i] = vector<int>(w);
			visited[i] = vector<bool>(w);
		}
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				cin >> v[i][j];
			}
		}
		int count = 0;
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				if (v[i][j] == 1 && !visited[i][j]) {
					count++;
					queue<pair<int, int>> q;
					q.push(make_pair(i, j));
					while (!q.empty()) {
						pair<int, int> cur = q.front();
						q.pop();
						if (!visited[cur.first][cur.second]) {
							visited[cur.first][cur.second] = true;
							if (cur.first + 1 < h && cur.second + 1 < w && !visited[cur.first + 1][cur.second + 1] && v[cur.first + 1][cur.second + 1] == 1) {
								q.push(make_pair(cur.first + 1, cur.second + 1));
							}
							if (cur.first + 1 < h && cur.second - 1 >= 0 && !visited[cur.first + 1][cur.second - 1] && v[cur.first + 1][cur.second - 1] == 1) {
								q.push(make_pair(cur.first + 1, cur.second - 1));
							}
							if (cur.first - 1 >= 0 && cur.second + 1 < w && !visited[cur.first - 1][cur.second + 1] && v[cur.first - 1][cur.second + 1] == 1) {
								q.push(make_pair(cur.first - 1, cur.second + 1));
							}
							if (cur.first - 1 >= 0 && cur.second - 1 >= 0 && !visited[cur.first - 1][cur.second - 1] && v[cur.first - 1][cur.second - 1] == 1) {
								q.push(make_pair(cur.first - 1, cur.second - 1));
							}
							if (cur.first + 1 < h && !visited[cur.first + 1][cur.second] && v[cur.first + 1][cur.second] == 1) {
								q.push(make_pair(cur.first + 1, cur.second));
							}
							if (cur.first - 1 >= 0 && !visited[cur.first - 1][cur.second] && v[cur.first - 1][cur.second] == 1) {
								q.push(make_pair(cur.first - 1, cur.second));
							}
							if (cur.second + 1 < w && !visited[cur.first][cur.second + 1] && v[cur.first][cur.second + 1] == 1) {
								q.push(make_pair(cur.first, cur.second + 1));
							}
							if (cur.second - 1 >= 0 && !visited[cur.first][cur.second - 1] && v[cur.first][cur.second - 1] == 1) {
								q.push(make_pair(cur.first, cur.second - 1));
							}
						}
					}
				}
			}
		}
		cout << count << endl;
	}
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1010번 다리 놓기  (0) 2020.02.07
[백준] 1026번 보물  (0) 2020.02.07
[백준] 1912번 연속합  (0) 2020.02.06
[백준] 2656번 전깃줄  (0) 2020.02.06
[백준] 11054번 가장 긴 바이토닉 부분 수열  (0) 2020.02.06
728x90
 

1912번: 연속합

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

www.acmicpc.net

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

int main() {
	cin.tie(NULL);
	int n;
	cin >> n;
	vector<int> inputNumbers(n);
	for (int i = 0; i < n; i++) {
		cin >> inputNumbers[i];
	}
	vector<int> sum(n);
	int maxSum = inputNumbers[0];
	sum[0] = inputNumbers[0];
	for (int i = 1; i < n; i++) {
		if (sum[i - 1] + inputNumbers[i] > inputNumbers[i])
			sum[i] = sum[i - 1] + inputNumbers[i];
		else 
			sum[i] = inputNumbers[i];
		if (sum[i] > maxSum) maxSum = sum[i];
	}
	cout << maxSum;
	return 0;
}

 

입력이 다음과 같이 들어왔을 때의 예를 살펴보자.

8
3 5 -3 2 2 -33 7 3 

앞에서부터 차례로 연속합을 구해서 i까지의 최대 연속 합을 sum[i]에 저장하고 최대 연속합이 나올 때마다 maxSum을 갱신하기로 하자.

양수를 더하면 항상 이득이기때문에 양수일 때에는 sum을 갱신한다.

sum[0] = 3, maxSum = 3

sum[1] = 8, maxSum = 8 이 된다.

하지만 그렇다고 음수인 -3을 더하면 sum[2]가 5로 줄어드니 새로 더해야 할까? 여기에서 멈춰야 할까?

계속 더하면

sum[2] = 5, maxSum = 8

sum[3] = 7, maxSum = 7

sum[4] = 9, maxSum = 9

이렇게 9를 얻을 수 있는데 새로 더하거나 멈추면 9를 놓치게 된다.

그럼 일단 음수가 나와도 계속 더하는 것으로 해보자.

sum[5] = -24, maxSum = 9

sum[6] = -17, maxSum = 9

sum[7] = -14, maxSum = 9

답은 maxSum인 9일까?

마지막에 7 3을 더하면 10이 나와서 정답은 10인데 9로 틀린 답을 내게 된다.

그럼 어떻게 했어야 할까?

-33까지 더하면 max[5] = -24, maxSum = 9이다.

그 다음 7이 나왔을 때 7부터 아예 새로 더하면 7이 될 것을 앞에서 구한 것을 굳이 연속해서 더해서 -17부터 시작할 필요는 없다. 부모가 빚을 물려준다면 아예 파산 신청을 하고 새로 시작하는 게 나은 것처럼 아예 7부터 새로 시작하도록 하자.

sum[6] = 7, maxSum = 9

sum[7] = 10, maxSum = 10

그러면 정답은 maxSum인 10이 된다.

 

그러면 언제 버리고 새로 시작해야 하는걸까?

앞에서 구한 연속 합에 나 자신을 더한 것보다 나 자신이 더 크다면 굳이 빚까지 상속받는 것보다는

나 자신부터 새로 시작하면 된다.

728x90
728x90
 

2565번: 전깃줄

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는 위치의 번호가 차례로 주어진다. 위치의 번호는 500 이하의 자연수이고, 같은 위치에 두 개 이상의 전깃줄이 연결될 수 없다.

www.acmicpc.net

왼쪽 전봇대 번호를 기준으로 오름차순 정렬한 후 LIS를 구하고 총 전깃줄 개수에서 LIS를 빼주었다.

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

int main() {
	int n;
	cin >> n;
	vector<pair<int, int>> line(n);
	for (int i = 0; i < n; i++) {
		int from, to;
		cin >> from >> to;
		line[i] = make_pair(from, to);
	}
	sort(line.begin(), line.end());
	vector<int> dp(n);
	dp[0] = 1;
	for (int i = 1; i < n; i++) {
		int maxLength = 0;
		for (int j = 0; j < i; j++) {
			if (line[i].second > line[j].second && dp[j] > maxLength)
				maxLength = dp[j];
		}
		dp[i] = maxLength + 1;
	}
	int lis = 0;
	for (int i = 0; i < n; i++) {
		if (dp[i] > lis) lis = dp[i];
	}
	cout << n - lis;
	return 0;
}
728x90
728x90

단계별로 풀어보기 동적계획법 1의 12단계 문제

 

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

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

www.acmicpc.net

LIS는 앞에서부터 구해서 increasingDp에 저장했고 LDS는 뒤에서부터 구해서 decreasingDp에 저장했다.

그리고 bitonicDp는 그 increasingDp[i]와 decreasingDp[i]를 더하고 i번째 수는 중복되어 세었으니 1을 빼주었다.

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

int main() {
	int n;
	cin >> n;
	vector<int>	v(n);
	for (int i = 0; i < n; i++) {
		cin >> v[i];
	}
	vector<int> increasingDp(n);
	vector<int> decreasingDp(n);
	increasingDp[0] = 1;
	for (int i = 1; i < n; i++) {
		int maxLength = 0;
		for (int j = 0; j < i; j++) {
			if (v[j] < v[i] && increasingDp[j] > maxLength) {
				maxLength = increasingDp[j];
			}
		}
		increasingDp[i] = maxLength + 1;
	}
	decreasingDp[n - 1] = 1;
	for (int i = n - 1; i >= 0; i--) {
		int maxLength = 0;
		for (int j = n - 1; j > i; j--) {
			if (v[i] > v[j] && decreasingDp[j] > maxLength) {
				maxLength = decreasingDp[j];
			}
		}
		decreasingDp[i] = maxLength + 1;
	}
	vector<int> bitonicDp(n);
	for (int i = 0; i < n; i++) {
		bitonicDp[i] = increasingDp[i] + decreasingDp[i] - 1;
	}
	int maxDp = 0;
	for (int i = 0; i < n; i++) {
		if (bitonicDp[i] > maxDp) maxDp = bitonicDp[i];
	}
	cout << maxDp;
	return 0;
}
728x90

'알고리즘 문제' 카테고리의 다른 글

[백준] 1912번 연속합  (0) 2020.02.06
[백준] 2656번 전깃줄  (0) 2020.02.06
[백준] 11651번 좌표 정렬하기 2  (0) 2020.02.06
[백준] 2583번 영역 구하기  (0) 2020.02.06
[백준] 2468번 안전영역  (0) 2020.02.06
728x90
실행 ctrl + shift + F10
메소드 매개변수 보기 인자가 들어갈 괄호 안에 마우스 커서 놓고 ctrl+p
메인 메소드 만들기 psvm+Enter
마우스 커서 위치와 상관 없이 개행 shift+Enter
자동완성 ctrl+Enter
해당 이름을 가진 변수 전체를 다른 이름으로 바꾸기 바꾸고 싶은 변수 이름을 더블클릭 또는 드래그 해서 선택한 후 shift + F6 누르고 원하는 변수 입력 후 Enter
//으로 주석처리 및 //으로 된 주석처리 해제 주석처리 또는 해제하고 싶은 행들을 선택한 후 ctr+/
/**/으로 주석처리 및 /**/으로 된 주석처리 해제 주석처리 또는 해제하고 싶은 부분을 선택한 후 ctrl+shift+/
코드 정렬 ctrl + alt + l
코드 완성 ctrl+shift+Enter
728x90

+ Recent posts