그럴듯한 개발 블로그
반응형

https://www.acmicpc.net/problem/2879

 

2879번: 코딩은 예쁘게

첫째 줄에 줄의 개수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 현재 줄에 있는 탭의 개수가 주어지며, 1번째 줄부터 순서대로 주어진다. 탭의 개수는 0보다 크거나 같고, 80보다 작거나 같은 정수

www.acmicpc.net

start부터 drag까지 1씩 뺐을때, 더했을때 비교해서 매 순간 제일 효율적인 상황으로 간다.

#include <iostream> // 실패코드
#include <string>
#include <vector>
#include <algorithm>
#include <deque>
#include <unordered_set>
#include <cstring>
#include <utility>

using namespace	std;
vector<int> src, dst;
int res = 0, num;

bool isOk() {
	for (int i = 0; i < num; i++)
		if (src[i] != dst[i])
			return false;
	return true;
}

void	greedy(int start, int drag) {
	int prevDiff = 2147483647;
	while (true) {
		int curDiff = 0, plusDiff = 0, minusDiff = 0;
		bool zeroFlag = false;
		for (int i = 0; i < drag; i++) {
			curDiff += abs(src[start + i] - dst[start + i]);
			plusDiff += abs(src[start + i] + 1 - dst[start + i]);
			if (src[start + i] == 0)
				zeroFlag = true;
			minusDiff += abs(src[start + i] - 1 - dst[start + i]);
		}
		if (prevDiff <= curDiff)
			return ;
		prevDiff = curDiff;
		if (isOk()) {
			cout << res;
			exit(0);
		}
		if (zeroFlag)
			minusDiff = 2147483647;
		int lessDiff = min(curDiff, min(plusDiff, minusDiff));
		if (lessDiff == curDiff)
			return ;
		else if (lessDiff == plusDiff) {
			res++;
			for (int i = 0; i < drag; i++)
				src[start + i]++;
		}
		else if (lessDiff == minusDiff) {
			res++;
			for (int i = 0; i < drag; i++)
				src[start + i]--;
		}
	}
}

int	main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

	cin >> num;
	for (int i = 0; i < num; i++) {
		int input;
		cin >> input;
		src.push_back(input);
	}
	for (int i = 0; i < num; i++) {
		int input;
		cin >> input;
		dst.push_back(input);
	}
	for (int drag = num; drag > 0; drag--)
		for (int start = 0; start + drag <= num; start++)
			greedy(start, drag);
}

그런데 테케2번인

4
1 2 3 4
3 1 1 0

여기서 문제가 생긴다. 

1 2 3 4 에서 1씩 다 뺀 0 1 2 3보다 2번째부터 1씩 다 뺀 1 1 2 3이 정답에 더 가깝다. 그렇다 거꾸로 생각해야한다.

단순히 저기서 drag가 1부터 시작하면 안된다. 그럼 죄다 드래그 1 짜리로 연산하기 때문이다.

 

1 3 3 2 에선 33

3 1 1 2 에선 11 이렇게 최댓값, 최솟값 꼭짓점들을 먼저 처리해주는 로직으로 조져봤다.

근데 역시 테케 2번에서 역시 탈락.. 이로직으론 최적해를 찾을 수 없다.

#include <iostream> // 실패코드
#include <string>
#include <vector>
#include <algorithm>
#include <deque>
#include <unordered_set>
#include <cstring>
#include <utility>

using namespace	std;
vector<int> diff;
int res = 0, num;
// 0 1 2 3 2
void topCase() {
	while (true) {
		int start = 0, end = 0;
		while (end < num - 1 && diff[end] <= diff[end + 1])
			end++;
		if (end == num - 1)
			return ;
		res++;
		start = end;
		while (start > 0 && diff[start - 1] == diff[end])
			start--;
		while (start <= end)
			diff[start++]--;
	}
}

void bottomCase() {
	while (true) {
		int start = 0, end = 0;
		while (end < num - 1 && diff[end] >= diff[end + 1])
			end++;
		if (end == num - 1)
			return ;
		res++;
		start = end - 1;
		while (start > 0 && diff[start - 1] == diff[end])
			start--;
		while (start <= end)
			diff[start++]++;
	}
}

int	main()
{
	vector<int> src, dst;
	cin >> num;
	for (int i = 0; i < num; i++) {
		int input;
		cin >> input;
		src.push_back(input);
	}
	for (int i = 0; i < num; i++) {
		int input;
		cin >> input;
		dst.push_back(input);
	}
	for (int i = 0; i < num; i++)
		diff.push_back(src[i] - dst[i]);
	// 위로 뾰족한거
	topCase();
	// // 아래로 뾰족한거
	bottomCase();
	// 이제 다 같은 수로 바뀌었을테니 그 차이만큼 더해준다.
	res += abs(diff[0]);
	cout << res;
}

//1 2 3 3 2 1

diff가 음수끼리 양수끼리 그룹을 만들어서 그 그룹의 최솟값만큼 더해주는 로직으로 해결했다. 이런 비슷한 문제 어디서 풀어봤던거 같은데.. 그리디 문제좀 많이 풀어봐야겠다.

#include <iostream> // 성공!
#include <string>
#include <vector>
#include <algorithm>
#include <deque>
#include <unordered_set>
#include <cstring>
#include <utility>

using namespace	std;
vector<int> diff;
int res = 0, num;

bool isAllZero(int start, int end) {
	for (int i = start; i <= end; i++)
		if (diff[i] != 0)
			return false;
	return true;
}

void drag(int start, int end) {
	int minEle, maxEle;

	minEle = *min_element(diff.begin() + start, diff.begin() + end + 1);
	maxEle = *max_element(diff.begin() + start, diff.begin() + end + 1);

	if (diff[start] > 0) { // 양수
		for (int i = start; i <= end; i++)
			diff[i] -= minEle;
		res += minEle;
	}
	else { // 음수
		for (int i = start; i <= end; i++)
			diff[i] -= maxEle;
		res -= maxEle;
	}
}

int	main()
{
	vector<int> src, dst;
	cin >> num;
	for (int i = 0; i < num; i++) {
		int input;
		cin >> input;
		src.push_back(input);
	}
	for (int i = 0; i < num; i++) {
		int input;
		cin >> input;
		dst.push_back(input);
	}
	for (int i = 0; i < num; i++)
		diff.push_back(src[i] - dst[i]);
	int start = 0, end = 0;
	while (start < num && isAllZero(start, num - 1) == false) {
		while (start < num && diff[start] == 0)
			start++;
		end = start;
		while (end + 1 < num && diff[start] * diff[end + 1] > 0) // 같은 부호
			end++;
		drag(start, end);
	}
	cout << res;
}
반응형

'<algorithm> > 백준' 카테고리의 다른 글

백준 1911 흙길 보수하기 c++  (1) 2023.10.14
백준 1459 걷기 c++  (0) 2023.10.12
백준 1026 보물 c++  (1) 2023.10.05
백준 2217 로프 c++  (0) 2023.10.05
백준 11559 Puyo Puyo c++  (1) 2023.10.01
profile

그럴듯한 개발 블로그

@donghyk2

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!