restore 문제 오답 케이스 조언 부탁드리겠습니다. zzerross RESTORE 문제 1주일째 풀고 있네요. 주로 검산가능한 작은 데이터 위주로 random data로 200개 정도 검토해 보고, coner case 수정했는데, 계속 오답으로 해매고 있습니다. 물론 최대 최소 긴 데이터들도 테스트해보긴 했구요. 최대한 스스로 풀어보려고 했건만, 몇일동안 못풀고 있어 질문 드립니다. (iteration DP로 느리진 않을꺼라 생각했는데, 많이 느리기까지 하네요..) 코드 로직은 아래와 같구요. cmp(): 문자열 y 뒤에 x가 올때, 겹칠 수 있는 길이를 저장해서 cp[][]에 저장 slv(): 모든 문자열 조합의 결과가 되는 문자열의 최소 길이를 dp table에 작성 trk(): dp table에 작성된 최소 조합을 tracking하며 최소 문자열 출력 소스코드는 아래와 같습니다. #include <stdio.h> #define ss 15 #define sc 41 #define sr (ss * sc) #define sf (1 << ss) #define nf ((1 << ns) - 1) int tc, ns, at[sc][sc]; char as[ss][sc]; struct cp { int l, x; } cp[ss][ss]; struct dp { int l, t; } dp[sf][ss]; struct q { int b[ss], r; } q; void read() { scanf("%d", &ns); for (int i = 0; i < ns; i++) scanf("%s", as[i]); } void cmp(int y, int x) { if (y == x) return; int i, j, k; for (i = 0; as[y][i]; i++) { for (j = 0; as[x][j]; j++) { at[i][j] = as[y][i] == as[x][j]; if (i && j) at[i][j] += at[i-1][j-1]; } } cp[y][x].l = 0; cp[y][x].x = -1; cp[y][y].l = i; cp[x][x].l = j; for (k = j-1; k >= 0; k--) { if (k == at[i-1][k] - 1) { cp[y][x].l = at[i-1][k]; cp[y][x].x = k; break; } } for (k = i-1; k >= 0; k--) { if (j == at[k][j-1]) { cp[y][x].l = j; cp[y][x].x = j; break; } } } void cmp() { for (int y = 0; y < ns; y++) for (int x = 0; x < ns; x++) cmp(y, x); } int slv() { for (int i = 0; i < ns; i++) dp[0][i].l = sr; for (int f = 1, l, b, t; f <= nf; f++) { for (int x = 0; x < ns; x++) { if (!(f & (1 << x))) continue; dp[f][x].t = -1; if (b = (f - (1 << x))) { dp[f][x].l = sr; } else { dp[f][x].l = cp[x][x].l; continue; } for (int y = 0; y < ns; y++) { if (!(b & (1 << y))) continue; t = cp[y][y].l == cp[dp[b][y].t][y].l ? dp[b][y].t : y; l = dp[b][y].l + cp[x][x].l - cp[t][x].l; if (dp[f][x].l > l) { dp[f][x].l = l; dp[f][x].t = y; } if (dp[f][x].t == -1) dp[f][x].t = y; } } } int m = 0; for (int i = 1; i < ns; i++) if (dp[nf][m].l > dp[nf][i].l) m = i; return m; } void trk(int i) { q.r = -1; for (int f = nf, t; i != -1; i = t) { q.b[++q.r] = i; t = dp[f][i].t; f -= (1 << i); } printf("%s", as[q.b[i = q.r]]); for (int y, x = 0, j, c = 1; --i >= 0;) { if (c) y = q.b[i+1]; x = q.b[i]; if (c = (cp[y][x].x != cp[y][x].l)) { j = cp[y][x].x + 1; printf("%s", &as[x][j]); } } printf("\n"); } int main() { for (scanf("%d", &tc); tc--;) { read(); cmp(); trk(slv()); } return 0; } 10년 전 4개의 댓글이 있습니다. Being 전체적으로 코드의 의도를 파악하기가 쉽지가 않습니다. 가장 중요한 "dp table" 부분에 대한 설명이 미흡한데다가, 코드는 다른 사람이 이해할 수 있도록 작성되어 있지 않아서 읽기 어렵습니다. 직전 단어와 그 전 단어만 참고하는 것으로 보이는 등 방법에 어느 정도 문제가 있는 것 같은데요, 아래 경우를 테스트해 보시기 바랍니다. 4 a b abc cd 10년 전 link zzerross 답변 감사합니다. 제시해 주신 케이스가 제대로 동작하지 않더군요. 그래서 수정했는데, (abcd 맞겠죠?) 여전히 오답이네요. 먼가 다른 오답케이스가 또 있나보네요. ^^; 케이스를 좀 더 테스트 해보도록 해야 겠네요... 책의 코드 복기/STL 없이 푸는게 도통 쉽지 않네요... 10년 전 link zzerross 지적해주신 코드의 가독성 부분...저도 인정하는 바이구요. ㅜ.ㅜ 허접하게나마 dp table 부분을 설명해보면 다음과 같습니다. _as: [0] a [1] b [2] abc [3] cd _cp: 0 1 2 3 0: 1, 0 0,-1 1, 0 0,-1 1: 0,-1 1, 0 0,-1 0,-1 2: 1, 1 1, 1 3, 0 1, 0 3: 0,-1 0,-1 0,-1 2, 0 _dp: m=3 : 0 1 2 3 0x 0: 0000: , , , , 0x 1: 1000: 1,-1 , , , 0x 2: 0100: , 1,-1 , , 0x 3: 1100: 2, 1 2, 0 , , 0x 4: 0010: , , 3,-1 , 0x 5: 1010: 3, 2 , 3, 0 , 0x 6: 0110: , 3, 2 4, 1 , 0x 7: 1110: 3, 2 3, 2 4, 0 , 0x 8: 0001: , , , 2,-1 0x 9: 1001: 3, 3 , , 3, 0 0x a: 0101: , 3, 3 , 3, 1 0x b: 1101: 4, 1 4, 0 , 4, 0 0x c: 0011: , , 5, 3 4, 2 <- 가로 축의 각 문자열을 0x d: 1011: 5, 2 , 5, 0 4, 2 마지막으로 포함한 0x e: 0111: , 5, 2 6, 1 4, 2 최소 길이, 그 전 문자열 0x f: 1111: 5, 2 5, 2 6, 0 4, 2 <- 최소 문자열 조합 q: 3 2 0 <- 위 dp table을 0xf의 최소값에서 부터 따라 올라감 abcd <- 위 q를 역순으로 중복되는 부분을 생략하여 출력 10년 전 link zzerross 겨우 오답 케이스 찾아서 정답 처리됐네요. 조언해 주신 Being 님 감사합니다. 지적해주신 케이스와 유사하게 여러 형태로 여러번 중첩되는 경우가 계속 문제였네요. 10년 전 link 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.
4개의 댓글이 있습니다. Being 전체적으로 코드의 의도를 파악하기가 쉽지가 않습니다. 가장 중요한 "dp table" 부분에 대한 설명이 미흡한데다가, 코드는 다른 사람이 이해할 수 있도록 작성되어 있지 않아서 읽기 어렵습니다. 직전 단어와 그 전 단어만 참고하는 것으로 보이는 등 방법에 어느 정도 문제가 있는 것 같은데요, 아래 경우를 테스트해 보시기 바랍니다. 4 a b abc cd 10년 전 link zzerross 답변 감사합니다. 제시해 주신 케이스가 제대로 동작하지 않더군요. 그래서 수정했는데, (abcd 맞겠죠?) 여전히 오답이네요. 먼가 다른 오답케이스가 또 있나보네요. ^^; 케이스를 좀 더 테스트 해보도록 해야 겠네요... 책의 코드 복기/STL 없이 푸는게 도통 쉽지 않네요... 10년 전 link zzerross 지적해주신 코드의 가독성 부분...저도 인정하는 바이구요. ㅜ.ㅜ 허접하게나마 dp table 부분을 설명해보면 다음과 같습니다. _as: [0] a [1] b [2] abc [3] cd _cp: 0 1 2 3 0: 1, 0 0,-1 1, 0 0,-1 1: 0,-1 1, 0 0,-1 0,-1 2: 1, 1 1, 1 3, 0 1, 0 3: 0,-1 0,-1 0,-1 2, 0 _dp: m=3 : 0 1 2 3 0x 0: 0000: , , , , 0x 1: 1000: 1,-1 , , , 0x 2: 0100: , 1,-1 , , 0x 3: 1100: 2, 1 2, 0 , , 0x 4: 0010: , , 3,-1 , 0x 5: 1010: 3, 2 , 3, 0 , 0x 6: 0110: , 3, 2 4, 1 , 0x 7: 1110: 3, 2 3, 2 4, 0 , 0x 8: 0001: , , , 2,-1 0x 9: 1001: 3, 3 , , 3, 0 0x a: 0101: , 3, 3 , 3, 1 0x b: 1101: 4, 1 4, 0 , 4, 0 0x c: 0011: , , 5, 3 4, 2 <- 가로 축의 각 문자열을 0x d: 1011: 5, 2 , 5, 0 4, 2 마지막으로 포함한 0x e: 0111: , 5, 2 6, 1 4, 2 최소 길이, 그 전 문자열 0x f: 1111: 5, 2 5, 2 6, 0 4, 2 <- 최소 문자열 조합 q: 3 2 0 <- 위 dp table을 0xf의 최소값에서 부터 따라 올라감 abcd <- 위 q를 역순으로 중복되는 부분을 생략하여 출력 10년 전 link zzerross 겨우 오답 케이스 찾아서 정답 처리됐네요. 조언해 주신 Being 님 감사합니다. 지적해주신 케이스와 유사하게 여러 형태로 여러번 중첩되는 경우가 계속 문제였네요. 10년 전 link 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.
zzerross
RESTORE
문제 1주일째 풀고 있네요.
주로 검산가능한 작은 데이터 위주로
random data로 200개 정도 검토해 보고,
coner case 수정했는데,
계속 오답으로 해매고 있습니다.
물론 최대 최소 긴 데이터들도 테스트해보긴 했구요.
최대한 스스로 풀어보려고 했건만, 몇일동안 못풀고 있어 질문 드립니다.
(iteration DP로 느리진 않을꺼라 생각했는데, 많이 느리기까지 하네요..)
코드 로직은 아래와 같구요.
소스코드는 아래와 같습니다.
10년 전
4개의 댓글이 있습니다.
Being
전체적으로 코드의 의도를 파악하기가 쉽지가 않습니다. 가장 중요한 "dp table" 부분에 대한 설명이 미흡한데다가, 코드는 다른 사람이 이해할 수 있도록 작성되어 있지 않아서 읽기 어렵습니다.
직전 단어와 그 전 단어만 참고하는 것으로 보이는 등 방법에 어느 정도 문제가 있는 것 같은데요, 아래 경우를 테스트해 보시기 바랍니다.
10년 전 link
zzerross
답변 감사합니다.
제시해 주신 케이스가 제대로 동작하지 않더군요.
그래서 수정했는데, (abcd 맞겠죠?)
여전히 오답이네요.
먼가 다른 오답케이스가 또 있나보네요. ^^;
케이스를 좀 더 테스트 해보도록 해야 겠네요...
책의 코드 복기/STL 없이 푸는게 도통 쉽지 않네요...
10년 전 link
zzerross
지적해주신 코드의 가독성 부분...저도 인정하는 바이구요. ㅜ.ㅜ
허접하게나마 dp table 부분을 설명해보면 다음과 같습니다.
10년 전 link
zzerross
겨우 오답 케이스 찾아서 정답 처리됐네요.
조언해 주신 Being 님 감사합니다.
지적해주신 케이스와 유사하게 여러 형태로 여러번 중첩되는 경우가 계속 문제였네요.
10년 전 link
정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.