단어를 첫글자와 마지막글자로 압축하고 재귀로 다음 단어가 가능하다면 진행하도록 했다.
매번 0~N-1 번째 단어를 모두 확인해야한다. (선택한 단어에 따라 가능한 단어가 바뀌기 때문)
이렇게 하면 16^16 인 것같다. 너무 많다. (16! 일수도 있는데 이것도 큼) 단어를 선택함에 있어서 순서만 다르고 조합이 같은 중복 선택(호출)이 분명 존재한다.
AE EA UA AU 같은 경우는 AE-EA-AU-UA 도 되지만, AU-UA-AE-EA 도 된다. (둘은 같다)
IE EE EI EO 는 EI-IE-EE-EO 도 되지만 EE-EI-IE-EO 도 된다. EO 입장에선 앞에서 무슨 순서로 오는 건 상관없다. 어떤 것을 사용했는가만 알면 된다.
N=16 이니까 n번째 단어를 사용했다/안했다고 표현하면 2^16 으로 표현이 가능하다. 그럼 재귀식은 (현재 위치, 이전까지 사용한 단어의 상황) 으로 중복을 제거할 수있다.
#include <bits/stdc++.h> using namespace std; int n, score[16]; char s[16][3]; bool visit[16]; int dp[16][1<<16+1]; int f(int pos, int bit){ if(pos >= n) return 0; int& r = dp[pos][bit]; if(r != -1) return r; r = 0; visit[pos] = true; for(int i=0; i<n; ++i){ if(!visit[i] && s[pos][1] == s[i][0]){ r = max(r, f(i, bit | (1<<i))); } } visit[pos] = false; return r += score[pos]; } int main(){ scanf("%d ", &n); for(int i=0; i<n; ++i){ char t[101]; scanf("%s ", t); s[i][0] = t[0]; s[i][1] = t[strlen(t)-1]; score[i] = strlen(t); } memset(dp, -1, sizeof(dp)); int r = 0; for(int i=0; i<n; ++i){ memset(visit, false, sizeof(visit)); int k = f(i, 1<<i); r = max(r, k); } printf("%d", r); return 0; }
댓글 1개:
좋은 글 감사합니다
댓글 쓰기