백준 1182번 (부분수열의 합, C++, DFS) / 추가 반례 [BAEKJOON]

단어 수학

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

시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초256 MB58135268021736444.381%

문제

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

입력

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

출력

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

예제 입력 1

5 0
-7 -3 -2 5 8

예제 출력 1

1

출처

알고리즘 분류


추가 예제

예제 입력 A

5 -3
-3 -2 -1 0 1

예제 출력 A

6

예제 입력 B

5 -2
-1 -1 -1 -1 -1

예제 출력 B

10

예제 입력 C

12 1000000
1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 -1000000

예제 출력 C

66

예제 입력 D

8 22
10 8 -6 6 0 10 5 3

예제 출력 D

6

실패 코드 1

#include <iostream>
#include <queue>
#include <algorithm> 

using namespace std;

int N, S, result;
// N 정수의 개수  1<= N <=20 
// S 목표값  |S| <= 1,000,000
// result 목표값과 같아지는 부분수열의 개수

#define MAX 20
// 많이 사용할 것 같아 매크로로 뚫어 놓음

int numbers[MAX] = { 0 };
// 수열들 0으로 초기화

struct MyStruct
{
	int sumNumber;
	int sNumbers[MAX];
}temp, temp2;

queue<MyStruct> myQueue;

// 입력 값을 받는 함수
void SettingConditions()
{
	cin >> N >> S;

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

void BFS()
{
	temp.sumNumber = 0;
	copy(numbers, numbers + MAX, temp.sNumbers);
	myQueue.push(temp);

	while (!myQueue.empty())
	{
		temp = myQueue.front();
		myQueue.pop();

		for (int i = 0; i < MAX; i++)
		{
			temp2 = temp;

			if (temp2.sNumbers[i] == 0)
			{
				continue;
			}

			int tempNumber = temp.sNumbers[i];
			temp2.sumNumber += temp.sNumbers[i];

			if (temp2.sumNumber == S)
			{
				result++;
			}
			temp2.sNumbers[i] = 0;
			myQueue.push(temp2);
		}
	}
}

int main()
{
	SettingConditions();
	BFS();

	cout << "결과 : " << result;
	return 0;
}

BFS로 접근

예제가

3 6
1 2 3 이라면

123 132
213 231
312 321

을 구분하지 못하는 난감한 상황이 발생하였다.

실패 코드 2

#include <iostream>
#include <queue>
#include <algorithm> 
#include <set>
#include <string>

using namespace std;

int N, S, result;
// N 정수의 개수  1<= N <=20 
// S 목표값  |S| <= 1,000,000
// result 목표값과 같아지는 부분수열의 개수

#define MAX 20
// 많이 사용할 것 같아 매크로로 뚫어 놓음

int numbers[MAX] = { 0 };
// 수열들 0으로 초기화

int resultarr[MAX];

struct MyStruct
{
	int sumNumber;
	int sNumbers[MAX];
	bool indexCheck[MAX] = {false};
	
}temp, temp2;

queue<MyStruct> myQueue;

// 입력 값을 받는 함수
void SettingConditions()
{
	cin >> N >> S;

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

void Test()
{
	for (int i = 0; i < N; i++)
	{
		cout << numbers[i] << " ";
	}
	cout << "\n";
}

void DFS()
{
	Test();

	temp.sumNumber = 0;
	copy(numbers, numbers + N, temp.sNumbers);
	myQueue.push(temp);
	while (!myQueue.empty())
	{
		temp = myQueue.front();
		myQueue.pop();
		

		for (int i = 0; i < N; i++)
		{
			temp2 = temp;
			
			if (temp2.indexCheck[i] == true)
			{
				continue;
			}

			temp2.sumNumber += temp2.sNumbers[i];
			if (temp2.sumNumber == S)
			{
				result++;
				continue;
			}
			temp2.indexCheck[i] = true;
			myQueue.push(temp2);


		}



	}

}

int main()
{
	SettingConditions();
	DFS();

	cout << result;
	return 0;
}

Set을 통한 체크 및 방문 처리
메모리 부족 시간 초과로 터짐

DFS 로 변경

성공 코드 (DFS)

#include <iostream>

using namespace std;

int N, S, result;

// 자주 사용할 것 같아 매크로로 등록 
#define MAX 20

int numbers[MAX];

void SettingCondition()
{
	result = 0;

	cin >> N >> S;

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

void DFS(int index, int total)
{
	if (index == N)
	{
		if (total == S)
		{
			result++;
			return;
		}
		//인덱스 마지막에 리턴
		return;
	}

	// 해당 인덱스의 원소를 사용할 때 / 안할 때
	DFS(index + 1, total + numbers[index]);
	DFS(index + 1, total);
}

int main()
{
	// 셋팅
	SettingCondition();
	DFS(0,0);
	
	// S = 0 이면 처음 시작 시 수열의 원소가 없지만 
	// total이 0 이므로 카운트가 하나 올라간다.
	if (S == 0) 
	{
		result--;
	}
	cout  << result;
	return 0;
}

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤