LAN 문제에 대해 질문 드립니다 wraithkim LAN문제를 풀다가 두가지 걸림돌이 있어서 질문드립니다. 지금 C++의 자료형과 문법을 약간 쓰고 있는데 C++ 지식 없습니다... (처음 질문해서 설명에 실수가 있을 수도 있습니다. 이해가 안되시면 물어봐주세요.) 시간 초과 지금 시간초과로 계속 틀리고 있는데 제 생각에는 더 이상 연산 과정이 줄어드는 방법이 없다고 생각하는데 이러면 알고리즘을 갈아 엎는게 맞는 건가요... 오차 예제 출력을 하면 10-7 이상에서 오차가 생기는데, 원인을 모르겠습니다. 예상으론 제 루트 계산법이 문제이거나 아니면 프림 알고리즘을 잘못 응용해서 최솟값이 아닌 값이 나오는 것 같은데 건물 사이의 거리가 정수가 아니라서 계산할 엄두가.... 안 나네요... #include <stdio.h> #define SQR_LEN(x, y) ((x)*(x))+((y)*(y)) float SQRT(float val) { float total = 1; for(int i = 0; i< 8; i++) { total = (total+(val/total))/2; } return total; } int main() { int num_case; float total_length[50]; //준비 과정 scanf("%d", &num_case); for(int i = 0; i < num_case; i++) //테스트 케이스(50번 이하) 루프 { int num_build, num_cable_installed; int p_build[500][2]; //건물의 좌표 int temp[3]; char graph_build[500][500] = { 0, }; //0: nonconnected c: connected a: already connected bool connected_build[500] = { 0, }; //첫 줄은 건물 개수(500개 이하)와 설치된 케이블 개수(2000개 이하) scanf("%d %d", &num_build, &num_cable_installed); //건물들의 x좌표 for(int j = 0; j < num_build; j++) { scanf("%d ", &p_build[j][0]); } //건물들의 y좌표(좌표는 전부 1000이하) for(int j = 0; j < num_build; j++) { scanf("%d ", &p_build[j][1]); } //설치된 케이블 하나당 연결된 건물... for(int j = 0; j < num_cable_installed; j++) { scanf("%d %d", &temp[0], &temp[1]); graph_build[temp[0]][temp[1]] = graph_build[temp[1]][temp[0]] = 'a'; } //해결 과정 //프림 알고리즘 응용 //출발점 하나를 지정한다. //만약 지금 이어진 노드가 이미 이어진 케이블이 있으면 그 노드도 연결시킨다. //기본적으론 지나간 점들에 이어진 에지 중 최솟값을 다음 이어진 노드로 정한다. //출발점은 건물 0번 //가장 큰 루프는 전체 건물이 케이블로 이어져 있을 때 탈출 //연결된 노드가 새로 생기면 루프는 지금 노드에서 이미 설치된 케이블이 있는지 확인한다. //있으면 자동으로 트리에 연결한다. //루프는 지금 지나간 모든 노드에서 가장 최소 에지를 찾는다 //단 시작노드와 끝노드가 전부 지나간 노드인 경우는 제외한다.(트리에 속해있으므로) //새로 이어질 최소 에지는 총 설치해야할 케이블 길이에 추가한다. connected_build[0] = true; //출발점 지정 total_length[i] = 0; while(true) { //연결된 노드 중 이미 설치된 케이블이 있는지 확인하는 루프 while(true) { bool is_end = true; for(int j = 0; j < num_build; j++) { for(int k = j; k < num_build; k++) { if((connected_build[j] || connected_build[k]) && graph_build[j][k] == 'a') { graph_build[j][k] = 'c'; connected_build[k] = connected_build[j] = true; is_end = false; break; } } } if(is_end) break; } //모든 건물이 연결되어 있는가 bool is_all_connect = true; for(int j = 0; j < num_build; j++) { if(!connected_build[j]) { is_all_connect = false; break; } } if(is_all_connect) break; //해결 루프 탈출 else { //최소 에지 찾기 temp[2] = 0; //temp: [0] = 최소 에지의 시작노드, [1] = 최소 에지의 끝노드, [2] = 최소 에지의 길이의 제곱 for(int j = 0; j < num_build; j++) {//이어진 노드 찾기 for(int k = j; k < num_build; k++) { if(connected_build[j] || connected_build[k]) { if(connected_build[j] && connected_build[k]) //이미 연결된 노드는 제외 continue; if(!temp[2])//temp값 초기화 { temp[0] = j; temp[1] = k; temp[2] = SQR_LEN(p_build[k][0] - p_build[j][0], p_build[k][1] - p_build[j][1]); continue; } if(temp[2] > SQR_LEN(p_build[k][0] - p_build[j][0], p_build[k][1] - p_build[j][1])) { temp[0] = j; temp[1] = k; temp[2] = SQR_LEN(p_build[k][0] - p_build[j][0], p_build[k][1] - p_build[j][1]); } } } } //최소 에지에 케이블 연결 graph_build[temp[0]][temp[1]] = 'c'; connected_build[temp[0]] = connected_build[temp[1]] = true; total_length[i] += SQRT((float)temp[2]); } } //해결 과정 end } //출력: 각 케이스 당 설치할 케이블들의 최소 합 for(int i = 0; i < num_case; i++) { printf("%.12f\n", total_length[i]); } return 0; } 11년 전
1개의 댓글이 있습니다. Kureyo 1)알고리즘 자체는 모르겠으나 프림구현부터 비효율적입니다..ㅠㅜ 최외각 while (true)안의 2중 루프들을 다 1중 루프이하로 줄일 수 있어보입니다 2)math 라이브러리의 sqrt함수를 사용하시는게.. 11년 전 link 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.
wraithkim
LAN문제를 풀다가 두가지 걸림돌이 있어서 질문드립니다.
지금 C++의 자료형과 문법을 약간 쓰고 있는데 C++ 지식 없습니다...
(처음 질문해서 설명에 실수가 있을 수도 있습니다. 이해가 안되시면 물어봐주세요.)
시간 초과
지금 시간초과로 계속 틀리고 있는데 제 생각에는 더 이상 연산 과정이 줄어드는 방법이 없다고 생각하는데
이러면 알고리즘을 갈아 엎는게 맞는 건가요...
오차
예제 출력을 하면 10-7 이상에서 오차가 생기는데, 원인을 모르겠습니다. 예상으론 제 루트 계산법이 문제이거나
아니면 프림 알고리즘을 잘못 응용해서 최솟값이 아닌 값이 나오는 것 같은데 건물 사이의 거리가 정수가 아니라서
계산할 엄두가.... 안 나네요...
11년 전