노드들은 힙트리를 사용해서
가장 작은 distance? (해당 노드까지의 노이즈 최소 값) 을
가지는 노드가 root에 오도록 했습니다.
edge들은 2*M개를 만들어 n1-n2, n2-n1를 모두 가지고 있고
n1값이 작은 값에서 큰 순서대로 소팅했습니다.
조언 부탁드립니다.
#include<stdio.h>#include<stdlib.h>intC,N,M;intnum_visit=0;typedefstructNode{intno;// node의 번호//정렬된 edge 배열에서 해당 노드가 포함되는 edge가 시작되는 indexintstart;// 정렬된 edge 배열에서 해당 노드가 포함되는 edge가 끝나는 indexintend;doubledistance;// 해당 노드까지 오는 최소 cost}NODE;typedefstructEdge{intn1;// 시작 노드intn2;// 끝 노드 doublew;// edge의 distance// 다익스트라 알고리즘에서 edge 사용 유무. 한번 사용했으면 trueboolvisit;}EDGE;NODEheap_nodes[10010];// 노드들을 힙트리? 우선순위큐? 형태로 저장할때 쓰이는 배열intheap_end;// edge들을 저장해놓은 배열. //n1 크기가 작은 순서에서 큰 순서대로 정렬되어 있음EDGEedges[50000];// 이 배열의 index에 해당하는 노드가, //heap_nodes에서 무슨 index에 저장되어있는지 가지고 있음// e.g.) heap_idx[5] = 10 -> //5번 노드는 heap_nodes 배열에서 10번에 저장되어있음intheap_idx[10010];// 각 노드의 각 노드까지 오는 최소 cost// e.g.) distance[5] = 10 -> 5번 노드까지 오는 최소 cost는 10doubledistance[10010];// 힙트리에서 노드 스왑 + // 힙트리에서의 인덱스 저장해놓은 배열에서도 스왑voidswap(intidx1,intidx2){NODEtmp2;inttmp;//node들의 heap 배열에서의 index 교환tmp=heap_idx[heap_nodes[idx1].no];heap_idx[heap_nodes[idx1].no]=heap_idx[heap_nodes[idx2].no];heap_idx[heap_nodes[idx2].no]=tmp;//heap 배열에서 노드 교환tmp2=heap_nodes[idx1];heap_nodes[idx1]=heap_nodes[idx2];heap_nodes[idx2]=tmp2;}// 가장 distance가 작은 노드가 root에 있는 트리 만들기// heap_nodes 배열로 구현. 배열 1번이 root.voidpush(NODEn){heap_end++;heap_nodes[heap_end]=n;heap_idx[n.no]=heap_end;if(heap_end>1){intidx=heap_end;intparent=heap_end/2;while(heap_nodes[parent].distance>heap_nodes[idx].distance){swap(idx,parent);idx=parent;parent=idx/2;if(parent==0)break;}}}// 가장 distance가 작은 노드 return -> heap_nodes[1] return.NODEpop(){NODEret=heap_nodes[1];heap_idx[heap_nodes[1].no]=-1;heap_nodes[1]=heap_nodes[heap_end];heap_idx[heap_nodes[heap_end].no]=1;heap_end--;intparent=1;intch1=2;while(1){if(heap_nodes[ch1].distance>heap_nodes[ch1+1].distance)ch1++;if(heap_nodes[ch1].distance<heap_nodes[parent].distance){swap(parent,ch1);parent=ch1;ch1=parent*2;}elsebreak;if(ch1>heap_end)break;}returnret;}//다익스트라 알고리즘 수행시 노드의 distance가 수정 될 경우, //수정한 뒤에//힙트리에서 노드의 위치가 바뀌어야 한다면 바꾸는 함수voidedit(intidx,doublew){//노드 distance 수정heap_nodes[idx].distance=w;//힙트리에서 위치 다시 찾기//distance가 현재 값에서 작아지기만 하므로 //parent보다 작은지만 계속 검사intparent=idx/2;while(parent>0){if(heap_nodes[parent].distance>heap_nodes[idx].distance){swap(parent,idx);}elsebreak;idx=parent;parent=idx/2;}}// merge sort. edge 정렬에 사용EDGEtmp[40000];voidmerge(intleft,intmid,intright){intl=left;intr=mid+1;intidx=0;while(l<=mid&&r<=right){if(edges[l].n1<edges[r].n1)tmp[idx++]=edges[l++];elseif(edges[l].n1>edges[r].n1)tmp[idx++]=edges[r++];else{if(edges[l].n2<=edges[r].n2)tmp[idx++]=edges[l++];elsetmp[idx++]=edges[r++];}}while(l<=mid)tmp[idx++]=edges[l++];while(r<=right)tmp[idx++]=edges[r++];for(inti=left;i<=right;i++)edges[i]=tmp[i-left];}voidmerge_sort(intleft,intright){if(left<right){intmid=(left+right)/2;merge_sort(left,mid);merge_sort(mid+1,right);merge(left,mid,right);}}intmain(){inta,b;doublec;scanf("%d",&C);while(C--){//input N: 노드수, M: edge수scanf("%d %d",&N,&M);// edge 입력for(inti=0;i<M;i++){scanf("%d %d %lf",&a,&b,&c);// a,b 중 작은 값을 n1에 입력하도록 했다. if(a<b){edges[i].n1=a;edges[i].n2=b;}else{edges[i].n1=b;edges[i].n2=a;}edges[i].w=c;edges[i].visit=false;}// 대칭 되는 edge도 만들어두기. a-b, b-afor(inti=M;i<M+M;i++){edges[i].n1=edges[i-M].n2;edges[i].n2=edges[i-M].n1;edges[i].w=edges[i-M].w;edges[i].visit=false;}// edge 정렬. n1 크기 순으로merge_sort(0,M+M-1);//모든 노드의 distance 큰 값으로 설정 뒤 힙트리에 PUSHintj,next=0;heap_end=0;for(inti=0;i<N;i++){NODEnode;node.distance=9999999999.0;node.no=i;distance[i]=9999999999.0;//해당 노드가 포함되는 edge의 edges배열에서 //시작 index와 끝 index 알아놓기intflag=0;for(j=next;j<M+M;j++){if(edges[j].n1==i&&flag==0){node.start=j;flag=1;}elseif(edges[j].n1!=i&&flag==1){node.end=j-1;next=j;break;}}if(j==M+M)node.end=j-1;push(node);}// 0번 노드의 distance를 1로 설정distance[0]=1;// node의 distance가 바뀌었으므로, //힙트리에서 노드 distance 바꾸고 위치 재설정edit(heap_idx[0],1);//총 방문한 노드 수. 이제 1개 방문했음num_visit=1;////////////////////////////////////////////////// Dijkstraintstart,end;NODEmin_node;while(1){//힙트리에서 distance가 가장 작은 node를 popmin_node=pop();//해당 노드가 가지고 있는 edge들 하나하나씩 보면서 //min_node와 연결된 node들의 distance 바뀌는지 검사. for(inti=min_node.start;i<=min_node.end;i++){//이미 한번 봤던 edge는 passif(edges[i].visit==true)continue;// EDGE=> [min_node] <-> [ii] intii;if(min_node.no==edges[i].n1)ii=edges[i].n2;elseii=edges[i].n1;if(distance[min_node.no]*edges[i].w<distance[ii]){distance[ii]=distance[min_node.no]*edges[i].w;edit(heap_idx[ii],distance[ii]);}edges[i].visit=true;}num_visit++;if(num_visit==N)break;}printf("%.10f\n",distance[N-1]);}return0;}
9년 전
0개의 댓글이 있습니다.
정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면
온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야
합니다. 현재 문제를 푸셨습니다.
freestar
너무 질문을 퍼붓는거 같아 민망 + 죄송합니다만..
정말 나름 이런저런 테스트 케이스 만들어보고 테스트 한 뒤에
올리는겁니다 ㅠㅠ
이번엔 ROUTING 질문입니다.
"오답"이 뜨는 중인데 왜 뜨는지 전혀 모르겠습니다.
핵심 알고리즘은 다익스트라 알고리즘을 사용했습니다.
노드들은 힙트리를 사용해서
가장 작은 distance? (해당 노드까지의 노이즈 최소 값) 을
가지는 노드가 root에 오도록 했습니다.
edge들은 2*M개를 만들어 n1-n2, n2-n1를 모두 가지고 있고
n1값이 작은 값에서 큰 순서대로 소팅했습니다.
조언 부탁드립니다.
9년 전