본문 바로가기
컴퓨터/Problem Solving

(BOJ, 1062) 가르침

by 빵케잌 2020. 1. 28.

실패코드 : O(2^n) Time Exceed

문자열을 26비트로 저장 + 개수 count를 비트로 연산은 좋았으나 ..

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int N, K;
char s[16];
int str[50];
int ans=0;
int cnt;

inline int get_size(int v) {
	int cnt = !!v;
	while (v &= v - 1)cnt++;
	return cnt;
};
void dfs(int index, int val) {
	if (index == N) return;
	if (get_size(val | str[index]) <= K) {
		cnt++;
		if (cnt > ans)ans = cnt;
		dfs(index + 1, val | str[index]);
		cnt--;
	}
	dfs(index + 1, val);
}

int main() {
	scanf("%d %d\n", &N, &K);
	for (register int i = 0; i < N; i++) {
		scanf("%s", s);
		str[i] |= (1 << ('a' - 'a')) | (1 << ('n' - 'a')) | (1 << ('t' - 'a')) | (1 << ('i' - 'a')) | (1 << ('c' - 'a'));
		for (register int j = 0; s[j]; j++) {
			if (s[j] == 'a' || s[j] == 'n' || s[j] == 't' || s[j] == 'i' || s[j] == 'c')
				continue;
			str[i] |= (1 << (s[j] - 'a'));
		}
	}
	cnt = 0;
	dfs(0,0);
	printf("%d\n", ans);
	
	return 0;
}

문자열 50개를 넣을지말지 보다는(여기까지 본인 아이디어)

 

26개 알파벳으로 K개의 알파벳이 채택된다고 했을 때, 각각 케이스에서 문자열이 몇개 들어가는지 체크하여 max를 알아내면 된다. (해답) 최대 26C13 * 50개의 문자열 -> 최대 5억이면 가능

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int N, K;
char s[16];
int str[50];
int ans=0;
int check_bit;

int check() {
	int cnt = 0;
	for (register int i = 0; i < N; i++) {
		if (!(str[i] & ~check_bit))cnt++;
	}
	return cnt;
}
void dfs(int depth, int index) {
	if (K - depth > 26 - index) return;
	if (depth == K) {
		int ret = check();
		if (ret > ans) ans = ret;
		return;
	}

	for (register int i = index; i < 26; i++) {
		check_bit |= 1 << index;
		dfs(depth+1, i+1);
		check_bit &= ~(1 << index);
	}
}
int main() {
	scanf("%d %d\n", &N, &K);
	for (register int i = 0; i < N; i++) {

		scanf("%s", s);

		str[i] |= (1 << ('a' - 'a')) | (1 << ('n' - 'a')) | (1 << ('t' - 'a')) | (1 << ('i' - 'a')) | (1 << ('c' - 'a'));
		for (register int j = 0; s[j]; j++) {
			if (s[j] == 'a' || s[j] == 'n' || s[j] == 't' || s[j] == 'i' || s[j] == 'c')
				continue;
			str[i] |= (1 << (s[j] - 'a'));
		}
	}
	dfs(0,0);
	printf("%d\n", ans);
	
	return 0;
}

는 뭔가 느리다.. (400ms )

알고봤더니 조합에서 a n t i c 는 고정이므로 고려할 필요가 없다  21C10 * 50 = 1500만이면 가능

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int N, K;
char s[16];
int str[50];
int ans=0;
int check_bit;
int flag[26];

int check() {
	int cnt = 0;
	for (register int i = 0; i < N; i++) {
		if (!(str[i] & ~check_bit))cnt++;
	}
	return cnt;
}
void dfs(int depth, int index) {
	if (depth == K) {
		int ret = check();
		if (ret > ans) ans = ret;
		return;
	}
	for (register int i = index; i < 26; i++) {
		if (i == 'a' - 'a' || i == 'n' - 'a' || i == 't' - 'a' || i == 'i' - 'a' || i == 'c' - 'a') continue;
		if (K - depth > 26 - i) return;
		check_bit |= 1 << i;
		dfs(depth + 1, i + 1);
		check_bit &= ~(1 << i);
	}
}
int main() {
	scanf("%d %d\n", &N, &K);
	for (register int i = 0; i < N; i++) {
		scanf("%s", s);
		for (register int j = 0; s[j]; j++) {
			str[i] |= (1 << (s[j] - 'a'));
		}
	}
	check_bit |= (1 << ('a' - 'a')) | (1 << ('n' - 'a')) | (1 << ('t' - 'a')) | (1 << ('i' - 'a')) | (1 << ('c' - 'a'));
	if (K >= 5) {
		K -= 5;
		dfs(0, 0);
	}
	printf("%d\n", ans);
	
	return 0;
}

결과 : 16ms

'컴퓨터 > Problem Solving' 카테고리의 다른 글

200201 ex  (0) 2020.02.03
(BOJ, 1525) 퍼즐  (0) 2020.01.28
(BOJ, 1806) 부분합  (0) 2020.01.27
(BOJ, 5052) 전화번호 목록  (0) 2020.01.27
(BOJ, 1753) 최단경로 (No Library)  (0) 2020.01.26