[Silver II] 부분수열의 합 - 1182
성능 요약
메모리: 21792 KB, 시간: 1260 ms
분류
브루트포스 알고리즘, 백트래킹
제출 일자
2024년 6월 1일 20:56:41
문제 설명
N개의 정수로 이루어진 수열이 있을 때, 크기가 양수인 부분수열 중에서 그 수열의 원소를 다 더한 값이 S가 되는 경우의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
출력
첫째 줄에 합이 S가 되는 부분수열의 개수를 출력한다.
💡 해결 방법
💻 코드
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
typedef struct Graph
{
int size;
int *data;
int *visited;
} Graph;
int graph_index(int a, int b)
{
return (int)pow(2, a) - 1 + b;
}
int find(Graph *graph, int target)
{
int temp_col = 0;
int temp_row = 0;
int temp_data = 0;
int count = 0;
int N = log2(graph->size + 1) - 1;
int size = pow(2, N);
int *answer = (int *)(calloc)(size, sizeof(int));
while (1)
{
if (graph->visited[graph_index(temp_col, temp_row)] != 1)
{
temp_data += graph->data[graph_index(temp_col, temp_row)];
graph->visited[graph_index(temp_col, temp_row)] = 1;
}
// 현재 위치의 visited 가 1이 아닌경우에만,
// 현재위치의 data를 누적으로 더하고, visited를 1로 기록한다 //0, 0 은 data가 0 이므로 의미 없음
if (temp_col == N) // 현재 위치가 leaf node인 경우
{
answer[temp_row] = temp_data;
}
if (temp_col + 1 <= N && 1 != graph->visited[graph_index(temp_col + 1, temp_row * 2)])
{
temp_col = temp_col + 1;
temp_row = temp_row * 2;
}
else if (temp_col + 1 <= N && 1 != graph->visited[graph_index(temp_col + 1, temp_row * 2 + 1)])
{
temp_col = temp_col + 1;
temp_row = temp_row * 2 + 1;
}
else
{ if(temp_col == 0) break;
temp_data -= graph->data[graph_index(temp_col, temp_row)];
temp_col = temp_col - 1;
temp_row = (temp_row) / 2;
}
// 현재 위치의 왼쪽, 오른쪽, 위 순서대로 visited 가 1 이 아닌 곳으로 이동한다.
// 위로 움직일떄에는 현재 위치의 data를 제거하면서 올라간다.
}
// // 다 끝나고 나면, answer을 출력해보자
// for (int a = 0; a < size; a++)
// {
// printf("%2d ", answer[a]);
// }
for(int a = 1, answer_sum = 0; a < size; a++)
{
if(answer[a] == target)
answer_sum ++;
if(a == size -1)
printf("%d", answer_sum);
}
return 0;
}
int main()
{
// 첫째 줄에 정수의 개수를 나타내는 N과
// 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000)
// 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
int N, S;
scanf("%d", &N);
scanf("%d", &S);
int *N_arr = (int *)malloc(sizeof(int) * N);
for (int a = 0; a < N; a++)
{
scanf("%d", &(N_arr[a]));
}
Graph *graph = (Graph *)malloc(sizeof(Graph));
graph->size = pow(2, N + 1) - 1;
graph->data = (int *)malloc(sizeof(int) * (graph->size));
graph->visited = (int *)calloc(graph->size, sizeof(int));
graph->data[0] = 0;
for (int col = 1, row = 0, temp = 0;; col++, temp++, row = 0)
{
for (; row < pow(2, col); row++)
{
if (row % 2 == 0)
graph->data[graph_index(col, row)] = 0;
else
graph->data[graph_index(col, row)] = N_arr[temp];
}
if (temp == N - 1)
break;
}
// for (int a = 0; a < N + 1; a++)
// {
// printf("[");
// for (int b = 0; b < pow(2, a); b++)
// {
// printf("%2d", graph->data[graph_index(a, b)]);
// }
// printf("]\n");
// }
find(graph, S);
}