| Linha | Codigo |
| 001 | // Prof. Leo^nidas - http://www.matematica.br http://line.ime.usp.br |
| 002 | // MAC0122 - 2017/10/30 |
| 003 | // Problema do caminho minimo: algoritmo de Dijkstra (proposto por Edsger W. Dijkstra em 1956) |
| 004 | |
| 005 | // Monta lista de adjacencia de um grafo, a partir de um arquivo no forma ("0 0" e' finalizador) |
| 006 | // k i k=numero de vertices, i indice do no de origem |
| 007 | // v1 ad11 custo11 ad12 custo12 ... 0 0 adjacentes ao vertice 1 (indice do adj. e custo da aresta) |
| 008 | // ... |
| 009 | // vk adk1 custok1 adk2 custok2 ... 0 0 idem para vertice k |
| 010 | |
| 011 | // gcc -fsanitize=address -g -o dijkstra dijkstra.c |
| 012 | |
| 013 | #include <stdio.h> |
| 014 | #include <stdlib.h> // para 'exit(N);' |
| 015 | #include <float.h> // FLT_MAX maior float positivo |
| 016 | |
| 017 | #define infinito FLT_MAX // superestimador (tem que ser maior que o custo de qualquer caminho) |
| 018 | #define MaxN 100 // maximo numero de nos |
| 019 | |
| 020 | #define LISTA 1 // Lista nos e adjacentes (para conferir o grafo) |
| 021 | |
| 022 | // Lista de adjacentes |
| 023 | typedef struct Lista { |
| 024 | int no; // numero do no' |
| 025 | int ind; // indice que o no' ocupara' em Adj[] |
| 026 | float ct; // se esta Lista corresponde ao no' <v>, entao <ct> = custo aresta (v,w), supondo w=Adj[ind] |
| 027 | struct Lista *prox; |
| 028 | } Lista; |
| 029 | |
| 030 | // Lista para o caminho minimo |
| 031 | typedef struct Caminho { |
| 032 | int no; // indice do no' |
| 033 | float d; // custo do no' |
| 034 | struct Caminho *prox; |
| 035 | } Caminho; |
| 036 | |
| 037 | Lista Adj[ MaxN ]; // lista de adjacencia para cada no' (Adj[i] = lista de adj ao no' de indice i) |
| 038 | Caminho C[ MaxN ]; // vetor para caminhos minimos (C[i] = lista de nos no cam. min. desde a origem ate' no' de indice i) |
| 039 | |
| 040 | // Redefine o caminho de <q>, C(q), como sendo (q,p)+C(p) |
| 041 | void TrocaC (Caminho *p, Caminho *q, float d) { |
| 042 | (*q).prox = p; |
| 043 | (*q).d = (*p).d+d; // d = verificaAdjacencia((*p).no,(*q).no) |
| 044 | } |
| 045 | |
| 046 | // Teste para saber se arquivo de entrada e' coerente (detecta erros do tipo: j aparecer na lista de i, mas i NAO aparecer na de j) |
| 047 | float verificaAdjacencia (int n1, int n2) { // <n2> deve ser adjacente 'a <n1> |
| 048 | Lista *V, *W; |
| 049 | V = Adj[n1].prox; // primeiro adjacente 'a <n1> |
| 050 | W = V; |
| 051 | while (W != NULL) { |
| 052 | if ((*W).no == n2) return W->ct; // ou: (*W).ct; |
| 053 | W = (*W).prox; // ou: W = W->prox; |
| 054 | } |
| 055 | printf("\nERRO: nos nao adjacentes, (%d, %d) nao pertence 'a AG\n", n1,n2); |
| 056 | return infinito; |
| 057 | } |
| 058 | |
| 059 | void ImprimeL (int n) { // Auxiliar: imprime lista de adjacentes ao no' de indice n |
| 060 | Lista *aux; |
| 061 | int i; |
| 062 | printf("\n Nos | Lista de adjacencias e custos"); |
| 063 | for (i=0; i<n; i++){ |
| 064 | aux = Adj[i].prox; |
| 065 | printf("\n No' %2d |", Adj[i].no); |
| 066 | while ( aux !=NULL ){ |
| 067 | printf(" (%d , %2.1f) ", (*aux).no, (*aux).ct); |
| 068 | aux = (*aux).prox; |
| 069 | } |
| 070 | } |
| 071 | } |
| 072 | |
| 073 | void imprimeHeap (int n, int hi[], float Hd[]) { // Auxiliar: lista vetor que dever ser um "heap" |
| 074 | int i, i_aux; |
| 075 | for (i=0; i<n; i++) { |
| 076 | i_aux = hi[i]; |
| 077 | if (Hd[ i_aux ] >= infinito) |
| 078 | printf("(%d,%d: %d, +oo) ", i, i_aux, C[i_aux].no); |
| 079 | else printf("(%d,%d: %d, %3.2f) ", i, i_aux, C[i_aux].no, Hd[ i_aux ]); |
| 080 | } |
| 081 | printf("\n"); |
| 082 | } |
| 083 | |
| 084 | void imprimeC (int origem, int n) { // Auxiliar: lista caminhos |
| 085 | int i; |
| 086 | Caminho *w; |
| 087 | printf("\nDistancias minimas ate o no [%d]", C[origem].no); |
| 088 | for (i=0; i<n; i++) { |
| 089 | printf("\n[%d] = %2.1f\n Caminho: ", C[i].no,C[i].d); |
| 090 | w = &C[i]; |
| 091 | do { |
| 092 | printf(" [%d]", (*w).no); |
| 093 | w = (*w).prox; |
| 094 | } while ( w != NULL ); |
| 095 | } |
| 096 | printf("\n"); |
| 097 | } |
| 098 | |
| 099 | // Computa distancia no caminho apontado por lstCam - para verificar ao final... |
| 100 | float DistanciaC (Caminho *lstCam) { |
| 101 | Caminho *lstCamAux = lstCam; |
| 102 | float aux = 0; |
| 103 | while ((*lstCamAux).prox != NULL) { |
| 104 | lstCam = lstCamAux; |
| 105 | lstCamAux = lstCamAux->prox; // ou: (*lstCamAux).prox; |
| 106 | aux += verificaAdjacencia(lstCam->no, lstCamAux->no); |
| 107 | } |
| 108 | return aux; |
| 109 | } |
| 110 | |
| 111 | |
| 112 | // Monta grafa a partir de arquivo com: |
| 113 | // linha 0: NG IND |
| 114 | // linha 1: g1 adj1_1 custo1_1 adj1_2 custo1_2 ... 0 0 |
| 115 | // ... |
| 116 | // linha NG: gN adjN_1 custoN_1 adjN_2 custoN_2 ... 0 0 |
| 117 | void MontaGrafo (int *N, int *nA, int *inicio, char *nome) { |
| 118 | FILE *arq; |
| 119 | Lista *aux, *ant; |
| 120 | int Ind[ (int)1.1*MaxN ]; // se no' <k> esta' em Adj[i] => Ind[k]=i |
| 121 | int i,n; |
| 122 | float ct; |
| 123 | //D int contaS = 0; |
| 124 | *nA = 0; |
| 125 | if ( (arq=fopen( nome,"r" )) == NULL ) { |
| 126 | printf("\nLamento, arquivo %s inexistente\n", nome); |
| 127 | exit(1); |
| 128 | } |
| 129 | if (LISTA) printf("\n Nos | Lista de adjacencias e custos"); |
| 130 | |
| 131 | fscanf(arq, "%d", N); |
| 132 | fscanf(arq, "%d", inicio); |
| 133 | |
| 134 | for (i=0; i<*N; i++) |
| 135 | Ind[ i ] = -1; // se posteriormente Ind[k] nao ficar pos. => ERRO |
| 136 | |
| 137 | // cada linha deve terminar com: 0 0 !!!!! |
| 138 | for (i=0; i<*N; i++) { |
| 139 | fscanf( arq, "%d ", &n); // numero do no' |
| 140 | // if ( feof(arq) ) return; se posicionar em final de arquivo! |
| 141 | Adj[i].no = n; // numero do no' |
| 142 | Adj[i].ind = i; // indice do no' |
| 143 | if ( n > (int)1.1*MaxN ) { |
| 144 | printf("\nErro: 1.1*MaxN nao suficiente para Ind[]\n"); |
| 145 | exit(1); |
| 146 | } |
| 147 | if (LISTA) printf("\n No' %2d |", Adj[i].no ); |
| 148 | |
| 149 | Ind[ n ] = i; |
| 150 | Adj[i].prox = NULL; |
| 151 | ant = NULL; |
| 152 | fscanf(arq,"%d %f", &n, &ct); |
| 153 | while ( n || ct ) { // montar adjacentes do i-esimo no' |
| 154 | aux = malloc( sizeof(Lista) ); |
| 155 | aux->no = n; |
| 156 | aux->ct = ct; |
| 157 | aux->prox = ant; |
| 158 | if (LISTA) printf(" (%d,%2.1f)", aux->no,aux->ct); |
| 159 | (*nA)++; |
| 160 | ant = aux; |
| 161 | fscanf(arq,"%d %f", &n, &ct); |
| 162 | //D if (contaS++>10) { printf("\nMontaGrafo: N=%d, contaS=%d\n", *N, contaS); exit(0); } |
| 163 | } |
| 164 | Adj[i].prox = ant; |
| 165 | } // for (i=0; i<*N; i++) |
| 166 | if (LISTA) printf("\n"); |
| 167 | for (i=0; i<*N; i++){ // Monta campo <ind> de todas as listas <Adj[]> |
| 168 | aux = Adj[i].prox; // primeiro adjacente do i-esimo no' |
| 169 | while (aux != NULL) { |
| 170 | n = (*aux).no; |
| 171 | if (Ind[n]==-1) { |
| 172 | printf("\nErro: i=%d, n=%d: Ind[%d]=-1 !!\n", i, n, n); |
| 173 | exit(1); |
| 174 | } |
| 175 | (*aux).ind = Ind[ n ]; |
| 176 | aux = (*aux).prox; |
| 177 | } |
| 178 | } |
| 179 | } // MontaGrafo |
| 180 | |
| 181 | |
| 182 | // ------------------------------------------------------------------------------------------------ |
| 183 | // Monta um "heap" a partir do ponto A[i]. Invariante: A[i+1], A[i+2],...,A[N-1] ja deve ser "heap" |
| 184 | // Propriedade de "heap": chave(i) <= min{ chave(filho_esq(i)), chave(filho_dir(i))} |
| 185 | |
| 186 | void troca (int i, int j, int hi[]) { |
| 187 | int aux; |
| 188 | aux = hi[i]; |
| 189 | hi[i] = hi[j]; |
| 190 | hi[j] = aux ; |
| 191 | } |
| 192 | |
| 193 | // Monta um "heap" a partir do ponto =hi[i], hi[i+1], hi[i+2],...,hi[N-1] ja deve ser Heap |
| 194 | // Neste "heap" o pai tem chave MENOR que dos filhos |
| 195 | void desceHeap (int i, int n, int hi[], float Hd[] ) { |
| 196 | int j, aux1; float aux2; |
| 197 | if (hi[i]<0 || hi[i]>MaxN) { printf("Erro em 'desceHeap': i=%d, hi[%d]=%d, MaxN=%d\n", i, i, hi[i], MaxN); exit(1); } |
| 198 | aux1 = hi[i]; aux2 = Hd[ hi[i] ]; |
| 199 | j = 2*i+1; |
| 200 | while ( j<n ) { |
| 201 | if ( j+1<n ) |
| 202 | if ( Hd[ hi[j+1] ] < Hd[ hi[j] ] ) j++; // "menor" filho |
| 203 | if ( Hd[ hi[j] ] < aux2 ) hi[i] = hi[j]; |
| 204 | else break; // termina o laco |
| 205 | i = j; |
| 206 | j = 2*j+1; |
| 207 | } |
| 208 | hi[i] = aux1; |
| 209 | } |
| 210 | |
| 211 | // Constroi o "heap" inicialmente (chave do pai menor que dos filhos) |
| 212 | void MontaHeap (int n, int hi[], float Hd[]) { |
| 213 | int i; |
| 214 | for (i=n/2; i>=0; i--) |
| 215 | desceHeap(i,n,hi,Hd); |
| 216 | } |
| 217 | // ------------------------------------------------------------------------------------------------ |
| 218 | |
| 219 | |
| 220 | // ------------------------------------------------------------------------------------------------ |
| 221 | // Entrada: lista de adjacencia <Lista V[]> |
| 222 | // Saida : arvore de caminhos <Caminho MontaC[]> |
| 223 | void Dijkstra (int indice, int NG, int NA) { |
| 224 | Lista *v; |
| 225 | int i_aux; // aux. para indices {0,1,...,NG-1} |
| 226 | int hi[ MaxN ]; // Vetor de ind. para nos de cam. min. desconhecido |
| 227 | float Hd[ MaxN ]; // Vetor de distancia para nos nao prontos |
| 228 | int i, j, min; |
| 229 | |
| 230 | for (i=0; i<NG; i++) { // Preparar distancias: C[i] sera a lista do caminho do no de <indice> ate no especifico |
| 231 | C[i].no = Adj[i].no; // pegue indice do no adjacentes |
| 232 | C[i].d = infinito; // arbitre que a distancia a cada no e' +oo |
| 233 | C[i].prox = NULL; |
| 234 | } |
| 235 | |
| 236 | // Definir distancia para no <indice> para outro <i> como o custo de sua aresta <indice, i> |
| 237 | C[ indice ].d = 0.0; // distancia de <indice> ate <indice> e' 0 |
| 238 | v = Adj[indice].prox; // inicio da lista de adjacencia do no <indice> |
| 239 | |
| 240 | // Constroi vetor NAO prontos - usara um Heap Hd[.], hi[.] |
| 241 | //D1 printf("Hd, hd: "); |
| 242 | hi[0] = indice; Hd[indice] = C[indice].d; |
| 243 | //D1 printf("(%d,%d: %d, %3.2f) ", 0, indice, C[indice].no, Hd[indice]); |
| 244 | j = 1; |
| 245 | for (i=0; i<NG; i++) |
| 246 | if (i!=indice) { |
| 247 | hi[j] = i; // indice do no |
| 248 | Hd[i] = infinito; // C[i].d; // distancia ate <indice> |
| 249 | //D1 printf("(%d,%d: %d, +oo) ", j, hi[j], C[hi[j]].no); |
| 250 | j++; |
| 251 | } |
| 252 | |
| 253 | //D1 printf("\n"); |
| 254 | |
| 255 | //D2 printf("Heap: NG=%d:\n ", NG); imprimeHeap(NG, hi, Hd); |
| 256 | |
| 257 | while (NG) { // NG>0 |
| 258 | min = hi[0]; // (hi,Hd) e Heap com minimo na raiz |
| 259 | //D3 printf("\nNG=%d, %d=min=hi[%d]=%d, Hd[%d]=%3.2f\n", NG, min, 0, hi[0], hi[0], Hd[min]); |
| 260 | //D3 printf("Heap: "); imprimeHeap(NG, hi, Hd); |
| 261 | v = Adj[min].prox; // inicio da lista de adjacencia do no' de indice 'min' - ?caminho na lista adj. de V[min]? |
| 262 | //D3 printf("Atualiza: "); |
| 263 | while (v!=NULL) { // atualiza distancia min. conhecida |
| 264 | i_aux = (*v).ind; |
| 265 | if ( C[ i_aux ].d > C[min].d + (*v).ct ) { |
| 266 | //D3 if (C[ i_aux ].d >= infinito) printf("(%d: %d, +oo) ", i_aux, C[i_aux].no); |
| 267 | //D3 else printf("(%d: %d, %3.2f) ", i_aux, C[i_aux].no, C[i_aux].d); |
| 268 | C[ i_aux ].d = C[min].d + (*v).ct; |
| 269 | C[ i_aux ].prox = &C[min]; |
| 270 | Hd[ i_aux ] = C[ i_aux ].d; |
| 271 | desceHeap(i_aux, NG, hi, Hd); |
| 272 | } |
| 273 | //D3 printf("\n"); |
| 274 | v = (*v).prox; |
| 275 | } |
| 276 | hi[0] = hi[NG-1]; |
| 277 | NG--; |
| 278 | desceHeap(0, NG, hi, Hd); |
| 279 | } |
| 280 | } // void Dijkstra(int indice, int NG, int NA) |
| 281 | // ------------------------------------------------------------------------------------------------ |
| 282 | |
| 283 | |
| 284 | int main (int argc, char *argv[]) { |
| 285 | int NG, NA, inicio; |
| 286 | printf("\nInicio\n"); |
| 287 | if (argc<2) { |
| 288 | printf("Falta o nome do arquivo com a descricao do Grafo\n./dijkstra nome_arq_dados.txt\n"); |
| 289 | return 1; |
| 290 | } |
| 291 | |
| 292 | MontaGrafo(&NG, &NA, &inicio, argv[1]); |
| 293 | |
| 294 | //D5 printf("\nDijkstra: NG=%d, NA=%d\n", NG, NA); |
| 295 | //D5 ImprimeL(NG); |
| 296 | |
| 297 | Dijkstra(inicio, NG, NA); // escolher como no iniciao o no' 1 |
| 298 | |
| 299 | imprimeC(inicio, NG); // Imprime caminhos minimos |
| 300 | |
| 301 | return 0; |
| 302 | } |