실험 데이터 복구하기 - Algospot(162)
- Posted at 2010/01/16 03:51
- Filed under Algorithm/Algospot
물론 이것저것 큰일들이 겹치게 되어 열심히 하지 않았던 것도 있지만...
이렇게 오래 try해본 문제는 정말 오랫만인것 같다.
이번 문제를 통해 뼈져리게 느낀점은 내가 만든 코드를 절대 맹신 하지 말자 는 것이다.
어느정도 가이드라인로 짰던 코드들은 전혀 문제가 없었고 순전히 내가 짜낸 알고리즘 코드만 문제가 있었단 사실... 디버깅만 2주;;
여러가지 testcase를 생각해보는것도 중요한듯...
계획으로 잡아놨던것도 뒤로 미루고 매달렸던 문제만큼 얻는것도 많았던것 같다.
pDNA와 비슷하게 재귀로 금방 풀었는데 바로 time limit
dp로 풀어봐야겠는데 이리저리 알아본 결과 TSP(traveling salesman problem)와 비슷하며 DP로 풀어보라는 ...
그래 이번기회에 dp공부를 좀 해보자는 생각으로 도전
처음엔 중간 중간 cost를 계산해 보겟다는 방식으로 접근했는데 문제되는게 한두가지가 아닌거 같아서 짜다가 관두고... 처음 cost를 정의할수 있는 방법으로 접근 잔여 길이으로만 weight를 정하고 마지막에 초기전체 길이를 잡아주면 될꺼 같았는데 이것역시 전부 포함 되는 것들이 문제 된다싶어서 다른방법을 생각했었는데 이게 삽질의 시작이었다. 나중에 한참 삽질하다가 어떤분한테 얘기들었던것은 전부포함되는건 그냥 제외시키면 되지 않느냐... 라는 말을 듣게 됐고;; 생각해보니 맞다... -_-;; 이것때문에 버린시간이.. ㅠㅠ
아무튼 어느정도 알고리즘은 윤곽이 잡혔는데 다음 문제되는것은 shortest path를 어떻게 저장시킬까 생각하는 것으로 한참 삽질후에 dynamic table 과 같은 table을 만들고 상위 node를 가리키는 방법으로 풀었다.
완성 됐다 싶어서 문자열들을 규칙에 맞게 조합시키는 루틴을 만들고 돌려보았다. testcase통과했는데 코드를 올려보니 WA .. 이걸로 보낸시간만 2주가 넘는다.
결정적으로 잔여 length 체크하는 부분과 조합시키는 부분을 짜내서 만들었는데 이부분에 예외처리가 아주 많이 안되었던것이었다. 결국 다양한 testcase로 디버깅 하고... 결국 오늘 Accept!!!
미칠듯한 쾌감이다!! '이제 미뤄놓은걸 할 수 있겠구나..' 라며...
소스 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
using namespace std;
char text[15][301];
char *mintext;
int path[15];
int weight[15][15];
int dist[15][(1 << 16)];
int via[15][1 << 16];
int idx;
int n;
int st;
int maxlen;
int length(char *st, char *ed);
int memoi(int sv, int set);
void johap(char *st, char *ed);
void get_path(int sv, int set);
int main(void)
{
int T;
cin >> T;
for (int tc = 0; tc < T; tc++) {
maxlen = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> text[i];
maxlen += strlen(text[i]);
}
mintext = (char *)malloc(maxlen + 1);
char *output;
output = (char *)malloc(maxlen + 1);
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (strcmp(text[i], text[j]) > 0) {
strcpy(output, text[i]);
strcpy(text[i], text[j]);
strcpy(text[j], output);
}
}
}
for (int i = 0; i < maxlen; i++)
mintext[i] = 'z';
mintext[maxlen + 1] = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
weight[i][j] = 0;
} else {
weight[i][j] = length(text[i], text[j]);
if (weight[i][j] == 0) {
for (int k = j; k < n - 1; k++) {
strcpy(text[k], text[k + 1]);
}
n--;
i = -1;
break;
}
}
}
}
int wmin = 100000;
int start = -1;
for (int i = 0; i < n; i++) {
memset(dist, -1, sizeof(dist));
memset(via, -1, sizeof(via));
idx = 0;
st = i;
int temp = strlen(text[i]) + memoi(i, (1 << n) - 1 - (1 << i));
if (temp < wmin) {
wmin = temp;
start = i;
path[idx++] = i;
get_path(i, (1 << n) - 1 - (1 << i));
//cout << "mintext1:" << mintext << endl;
memset(mintext, 0, sizeof(mintext));
//cout << "< " << i << endl;
for (int i = 0; i < n; i++) {
//cout << path[i] << ":";
johap(mintext, text[path[i]]);
}
//cout << endl;
//cout << "mintext2:" << mintext << endl;
} else if (temp == wmin) {
start = i;
path[idx++] = i;
get_path(i, (1 << n) - 1 - (1 << i));
memset(output, 0, sizeof(output));
//cout << "== " << i << endl;
for (int k = 0; k < n; k++) {
//cout << path[k] << ":";
johap(output, text[path[k]]);
}
//cout << endl;
//cout << "mintext:" << mintext << endl;
//cout << "output:" << output << endl;
if (strcmp(mintext, output) > 0) {
start = i;
strcpy(mintext, output);
}
}
}
cout << mintext << endl;
/*
cout << wmin << endl;
for (int i = 0; i < n; i++) {
cout << text[i] << endl;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << weight[i][j] << " ";
}
cout << endl;
}
*/
}
return 0;
}
void get_path(int sv, int set)
{
//cout << "[" << sv << "Path:" << via[sv][set] << "]" << endl;
path[idx++] = via[sv][set];
if (set == 0)
return;
get_path(via[sv][set], set - (1 << via[sv][set]));
}
int memoi(int sv, int set)
{
// 노드를 전부 돌았을때
if (set == 0) {
//return dist[sv][set] = weight[st][sv];
return dist[sv][set] = 0;
}
// 이미 돌았던 노드와 같은 상황이 온다면 저장되어있는 값을 리턴
if (dist[sv][set] != -1)
return dist[sv][set];
int tmin = 100000;
for (int i = 0; i < n; i++) {
if (((set & (1 << i)) != 0) && (i != sv)) {
//int temp = memoi(i, set - (1 << i));
int temp = weight[sv][i] + memoi(i, set - (1 << i));
if (temp < tmin) {
tmin = temp;
via[sv][set] = i;
}
}
}
return (dist[sv][set] = tmin);
}
int length(char *st, char *ed)
{
int st_len = strlen(st);
int ed_len = strlen(ed);
int i, j, k;
k = j = 0;
for (i = 0; i < st_len && j < ed_len; i++) {
if (st[i] == ed[j])
j++;
else {
if (j > 0)
i = k++;
j = 0;
}
}
//return st_len + (ed_len - j);
return (ed_len - j);
}
void johap(char *st, char *ed)
{
int st_len = strlen(st);
int ed_len = strlen(ed);
int i, j, k;
k = j = 0;
for (i = 0; i < st_len && j < ed_len; i++) {
if (st[i] == ed[j])
j++;
else {
if (j > 0)
i = k++;
j = 0;
}
}
for (int k = j; k < ed_len; k++) {
st[i++] = ed[k];
}
st[i] = 0;
}
실행 시간/메모리 제한
실행 시간: 2000ms, 메모리 제한: 65536KB문제 설명
토요일에 출근해서 연구실에서 놀고 있던 조교 A군은 실수로 실험에 사용하던 데이터를 삭제하고 말았다. 복사본도 없는 터라 이대로라면 교수님의 진노를 한 몸에 받을 것은 자명한 일, 따라서 A군은 그럴 듯해 보이는 데이터를 위조하여 (주: 실제로 이러면 안 됩니다) 교수님의 분노를 피해 가기로 한다.
우리가 데이터에 대해 알고 있는 것은, 데이터가 K개의 문자열을 부분 문자열로 포함한다는 것밖에 없다. 어떤 문자열의 부분 문자열은 해당 문자열의 연속된 일부분이라고 가정하자. 이 문자열들은 모두 알파벳 소문자로 구성된다. 이들을 모두 부분 문자열로 포함하는 문자열 중 가장 짧은 것을 계산하는 프로그램을 작성하라. 만약 이와 같은 문자열이 여러 개 있다면 이 중 가장 사전 순으로 앞에 오는 것을 찾도록 한다.
입력 설명
입력의 첫 줄에는 테스트 케이스의 수 C (<= 50) 이 주어진다. 각 테스트 케이스의 첫 줄에는 부분 문자열의 수 K (<= 15) 가 주어진다. 그 후 K 줄에 하나씩, 알파벳 소문자로만 구성된 부분 문자열이 주어진다.
원래 문자열의 길이는 300 이하이다.
출력 설명
각 테스트 케이스마다 한 줄로, 해당 문자열을 모두 포함하는 가장 짧은 문자열들 중 사전 순으로 가장 앞에 있는 것을 출력한다.
예제 입력
3 3 geo oji jing 2 world hello 3 abrac cadabra dabr
예제 출력
geojing helloworld cadabrac
'Algorithm > Algospot' 카테고리의 다른 글
| 실험 데이터 복구하기 - Algospot(162) (0) | 2010/01/16 |
|---|---|
| 콘서트 - Algospot(224) (0) | 2009/12/20 |
| 눈치게임 - Algospot(262) (0) | 2009/12/18 |
| Yulo.K 선생님의 고민 - Algospot(252) (0) | 2009/12/18 |
| URI Decoding - Algospot(110) (0) | 2009/12/18 |
| Weird Numbers - Algospot(101) (0) | 2009/12/05 |
- Tag
- 162, algorithm, Algospot, trynerr, 실험 데이터 복구하기
- Response
- 0 Trackback , 0 Comment