Cod sursa(job #2986158)

Utilizator MihaiZ777MihaiZ MihaiZ777 Data 27 februarie 2023 20:28:17
Problema Ubuntzei Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.54 kb
#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;

ifstream fin("ubuntzei.in");
ofstream fout("ubuntzei.out");

/* 
    Run dijkstra for all friends to condense the graph
    Build the new graph
    Run configuration dp on the new graph
*/ 

const int INF = 0x3f3f3f3f;
const int MAX_K = 18;
struct Edge
{
    int destination;
    int cost;

    bool operator < (const Edge& other) const {
        return cost > other.cost;
    }
};


vector <Edge> graph[2005];
vector <Edge> condensedGraph[MAX_K];
priority_queue <Edge> heap;
int distances[2005];
int friends[MAX_K];
int dp[1 << MAX_K][MAX_K];
int n, m, k;


void Dijkstra(int node) {
    Edge firstEdge = {node, 0};
    heap.push(firstEdge);

    memset(distances, INF, sizeof(distances));
    distances[node] = 0;

    while (!heap.empty()) {
        Edge edge = heap.top();
        heap.pop();

        for (Edge newEdge : graph[edge.destination]) {
            if (distances[newEdge.destination] <= distances[edge.destination] + newEdge.cost) {
                continue;
            }
            distances[newEdge.destination] = distances[edge.destination] + newEdge.cost;
            newEdge.cost = distances[newEdge.destination];
            heap.push(newEdge);
        }
    }
}

void BuildCondensedGraph(int friendsCount) {
    for (int i = 1; i <= friendsCount; i++) {
        int startFriendNode = friends[i];

        // Run Dijkstra for all friends
        Dijkstra(startFriendNode);

        for (int j = i + 1; j <= friendsCount; j++) {
            int finishFriendNode = friends[j];
            int distance = distances[finishFriendNode];

            // Build the condensed graph
            Edge condensedGraphEdge = {j, distance};
            condensedGraph[i].push_back(condensedGraphEdge);
            condensedGraphEdge = {i, distance};
            condensedGraph[j].push_back(condensedGraphEdge);
        }
    }
}

void BuildDynamicConfiguration(int nodesCount) {
    memset(dp, INF, sizeof(dp));

    dp[1][1] = 0;

    for (int conf = 1; conf < (1 << (nodesCount + 1)); conf += 2) {
        for (int node = 1; node <= nodesCount; node++) {
            if (dp[conf][node] == INF) {
                continue;
            }
            
            for (Edge edge : condensedGraph[node]) {
                // Check if it was visited
                if (conf & (1 << (edge.destination - 1))) {
                    continue;
                }
                
                // Mark new node in the configuration
                int newConf = conf ^ (1 << (edge.destination - 1));
                // Update the dp with the min
                dp[newConf][edge.destination] = min(dp[newConf][edge.destination], dp[conf][node] + edge.cost);
            }
        }
    }
}

int GetAnswer(int nodesCount) {
    return dp[(1 << nodesCount ) - 1][nodesCount];
}

int main() {
    fin >> n >> m;

    fin >> k;

    // Add start
    friends[1] = 1;
    k++;

    for (int i = 2; i <= k; i++) {
        fin >> friends[i];
    }

    for (int i = 1; i <= m; i++) {
        int a, b, c;
        fin >> a >> b >> c;

        Edge graphEdge = {b, c};
        graph[a].push_back(graphEdge);
        graphEdge = {a, c};
        graph[b].push_back(graphEdge);
    }

    // Add destination
    friends[++k] = n;
    
    BuildCondensedGraph(k);
    BuildDynamicConfiguration(k);
    int answer = GetAnswer(k);

    fout << answer << '\n';

    return 0;
}