Cod sursa(job #1590288)

Utilizator stoianmihailStoian Mihail stoianmihail Data 4 februarie 2016 20:56:54
Problema Ubuntzei Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.44 kb
#include <limits.h>
#include <stdio.h>
#include <vector>
#include <queue>

using std::priority_queue;
using std::vector;

#define Smerenie 20000
#define Nadejde 2000
#define MAX_K 15

typedef struct {
  int u, cost;
} pair;

typedef struct {
  int v, cost, next;
} list;

typedef struct {
  bool operator()(const pair &X, const pair &Y) {
    return (X.cost > Y.cost);
  }
} minHeap;

int N, M, K;
int shl[MAX_K];
int take[MAX_K];
int bits[MAX_K];
int adj[Nadejde + 1];
list l[Smerenie + 1];
int lg[(1 << MAX_K) + 1];
int d[MAX_K][(1 << MAX_K) + 1];
int dist[Nadejde + 1][Nadejde + 1];
priority_queue <pair, vector<pair>, minHeap> heap;

/** min(X, Y). **/
int MIN(int X, int Y) {
  return X < Y ? X : Y;
}

void addEdge(int u, int v, int cost, int pos) {
  l[pos].v = v;
  l[pos].cost = cost;
  l[pos].next = adj[u];
  adj[u] = pos;
}

/** Initializeaza "dist". **/
void init(int u) {
  int i;

  for (i = 1; i <= N; i++) {
    dist[u][i] = INT_MAX;
  }
}

/** Adauga in heap nodul "u". **/
void enqueue(int u, int source, int cost) {
  dist[source][u] = cost;
  heap.push({u, cost});
}

/** Da-mi urmatorul nod. **/
void dequeue(int *u, int *cost) {
  pair top = heap.top();
  (*u) = top.u;
  (*cost) = top.cost;
  heap.pop();
}

/** Calculeaza pentru fiecare nod distanta pana la nodul "source". **/
void dijkstra(int source) {
  int u, v, pos, cost, curr;

  init(source);
  enqueue(source, source, 0);
  while (!heap.empty()) {
    dequeue(&u, &cost);
    if (cost == dist[source][u]) {
      for (pos = adj[u]; pos; pos = l[pos].next) {
        v = l[pos].v;
        curr = cost + l[pos].cost;
        if (curr < dist[source][v]) {
          enqueue(v, source, curr);
        }
      }
    }
  }
}

/** Analizeaza submultimea "set". **/
void analyzes(int set) {
  int i, j, save, last, size = 0;

  if (set & (set - 1)) {
    for (save = set; save; save ^= last) {
      last = save & -save;
      bits[size++] = lg[last];
    }
    for (i = 0; i < size; i++) {
      d[bits[i]][set] = INT_MAX;
      for (j = 0; j < size; j++) {
        if (i != j) {
          d[bits[i]][set] = MIN(d[bits[i]][set], d[bits[j]][set ^ shl[bits[i]]] + dist[take[bits[i]]][take[bits[j]]]);
        }
      }
    }
  }
}

int main(void) {
  int i, u, v, cost;
  FILE *f = fopen("ubuntzei.in", "r");

  /* Citirea datelor. */
  fscanf(f, "%d %d %d", &N, &M, &K);
  for (i = 0; i < K; i++) {
    fscanf(f, "%d", &take[i]);
  }
  for (i = 1; i <= M; i++) {
    fscanf(f, "%d %d %d", &u, &v, &cost);
    addEdge(u, v, cost, i);
    addEdge(v, u, cost, i + M);
  }
  fclose(f);

  /* Construieste "dist". **/
  dijkstra(1);
  for (i = 0; i < K; i++) {
    dijkstra(take[i]);
  }

  /* Initilizarea dinamicii. */
  for (i = 0; i < K; i++) {
    shl[i] = 1 << i;
    d[i][shl[i]] = dist[1][take[i]];
    lg[shl[i]] = i;
  }

  /* Treci prin submultimi. */
  //fprintf(stderr, "...");
  int total = (1 << K) - 1;
  for (i = 1; i <= total; i++) {
    analyzes(i);
  }
/*
  for (register int u = 1; u <= N; u++) {
    fprintf(stderr, "Nodul %d: ", u);
    for (register int v = 1; v <= N; v++) {
      fprintf(stderr, "(%d, %d), ", v, dist[u][v]);
    }
    fprintf(stderr, "\n");
  }
*/
  /* Calcularea solutiei. */
  int min = INT_MAX;
  if (K == 0) {
    min = dist[1][N];
  } else for (i = 0; i < K; i++) {
    min = MIN(min, d[i][total] + dist[take[i]][N]);
  }

  /* Afisarea solutiei. */
  freopen("ubuntzei.out", "w", stdout);
  fprintf(stdout, "%d\n", min);
  fclose(stdout);

  /// Multumim Doamne!
  puts("Doamne ajuta!");
  return 0;
}