Cod sursa(job #1711358)

Utilizator manutrutaEmanuel Truta manutruta Data 31 mai 2016 01:11:37
Problema Arbore partial de cost minim Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 10.76 kb
/* ========================================================================
   $Creator: Emanuel Truta $
   $Notice: (C) Copyright 2016 by Emanuel Truta. All Rights Reserved. $
   ======================================================================== */

#include <vector>
#include <queue>
#include <algorithm>
#include <set>

// #include "manu_header.h"
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef int32_t b32;

#define internal static
#define local_persist static
#define global_variable static

#define Assert(Expression) if (!(Expression)) { *((int *)0) = 0; }
// manu_header

// #include "graph.cpp"
// #include "graph.h"
struct graph
{
    struct edge
    {
        u32 Node;
        i32 Cost;
    };
    typedef std::vector<edge>::iterator iter;
    

    u32 Size; // Holds the size of the
    u32 NEdges;
    b32 Directed; // Set to true if you need a directed graph.
    b32 ProvideReverse; // Set to true if you need the reverse graph.
    b32 StartIndex; // If for some reason you need the graph to be 1-indexed.

    std::vector< std::vector<edge> > Out; // Holds the graph edges.
    std::vector< std::vector<edge> > In; // Holds the reversed graph edges, if ProvideReverse is not 0. Holds nothing otherwise.
    

    // Reads a graph from a file. The file should have the format:
    // Size NumberOfEdges
    // Node1 Node2 Cost
    // Node1 Node2 Cost
    // ...
    void Read(char *Filename);
    b32 HasEdge(u32 Node1, u32 Node2); // Returns a boolean that is true if there is an edge from Node1 to Node2.
    i32 GetCost(u32 Node1, u32 Node2); // Get cost of an edge. If that edge does not exists, it returns 0xcccccccc;
    void SetCost(u32 Node1, u32 Node2, i32 NewCost); // Sets the cost of an edge. If the edge does not exist, nothing happens.


    // Generates a distance vector from Node1. Every entry in that distance is the distance from Node to that entry.
    // If there is no path from Node to a particular entry, then the distance vector will hold 0x3f3f3f3f for that entry.
    std::vector<u32> DoForwardBFS(u32 Node);
    std::vector<u32> DoBackwardBFS(u32 Node); // Same as DoForwardBFS, but does everything on the reversed graph.
    std::vector<u32> DoDijkstra(u32 Node); // Same as DoForwardBFS, but uses Dijkstra algorithm.
    u32 GetDistanceForwardBFS(u32 Node1, u32 Node2); // Gets the smallest path from Node1 to Node2 using ForwardBFS.
    u32 GetDistanceBackwardBFS(u32 Node1, u32 Node2); // Gets the smallest path from Node1 to Node2 using BackwardBFS.
    u32 GetDistanceDijkstra(u32 Node1, u32 Node2); // Gets the smallest path from Node1 to Node2 using Dijkstra.
    std::vector<u32> GetTopologicalSort();
};
// graph.h

// <parsing>
FILE *fin;
const int maxb = 8192;
char buf[maxb];
int ptr = maxb - 1;
 
int GetInt()
{
    int mul = 1;
    while (buf[ptr] < '0' || '9' < buf[ptr])
    {
        if (buf[ptr] == '-')
        {
            mul = -1;
        }
        if (++ptr >= maxb)
        {
            fread(buf, maxb, 1, fin);
            ptr = 0;
        }
    }
    int nr = 0;
    while ('0' <= buf[ptr] && buf[ptr] <= '9')
    {
        nr = nr * 10 + buf[ptr] - '0';
        if (++ptr >= maxb)
        {
            fread(buf, maxb, 1, fin);
            ptr = 0;
        }
    }
    return nr * mul;
} 
// </parsing>

void graph::
Read(char *Filename)
{
    // FILE *File = fopen(Filename, "r");
    fin = fopen(Filename, "r");

    u32 EdgesCount;
    // fscanf(File, "%d %d\n", &Size, &EdgesCount);
    Size = GetInt(); EdgesCount = GetInt(); NEdges = EdgesCount;
    Size += StartIndex;
    Out.resize(Size);
    if (ProvideReverse)
    {
        In.resize(Size);
    }

    for (u32 Index = 0; Index < EdgesCount; ++Index)
    {
        u32 X, Y;
        i32 Cost;

        // fscanf(File, "%d %d %d\n", &X, &Y, &Cost);
        X = GetInt(); Y = GetInt(); Cost = GetInt();

        if (Directed)
        {
            Out[X].push_back(edge{Y, Cost});
            if (ProvideReverse)
            {
                In[Y].push_back(edge{X, Cost});
            }
        }
        else
        {
            Out[X].push_back(edge{Y, Cost});
            Out[Y].push_back(edge{X, Cost});
        }
    }
}


b32 graph::
HasEdge(u32 Node1, u32 Node2)
{
    b32 Result = 0;

    for (iter It = Out[Node1].begin(); It != Out[Node1].end(); ++It)
    {
        if (It->Node == Node2)
        {
            Result = 1;
        }
    }
    
    return Result;
}


i32 graph::
GetCost(u32 Node1, u32 Node2)
{
    for (iter It = Out[Node1].begin(); It != Out[Node1].end(); ++It)
    {
        if (It->Node == Node2)
        {
            return It->Cost;
        }
    }

    return 0xcccccccc;
}


void graph::
SetCost(u32 Node1, u32 Node2, i32 NewCost)
{
    for (iter It = Out[Node1].begin(); It != Out[Node1].end(); ++It)
    {
        if (It->Node == Node2)
        {
            It->Cost = NewCost;
        }
    }

    if (Directed && ProvideReverse)
    {
        for (iter It = In[Node2].begin(); It != In[Node2].end(); ++It)
        {
            if (It->Node == Node1)
            {
                It->Cost = NewCost;
            }
        }
    }

    if (!Directed)
    {
        for (iter It = Out[Node2].begin(); It != Out[Node2].end(); ++It)
        {
            if (It->Node == Node1)
            {
                It->Cost = NewCost;
            }
        }
    }
}


std::vector<u32> graph::
DoForwardBFS(u32 Node)
{
    std::vector<u32> Dist;
    Dist.resize(Size);
    for (u32 I = 0; I < Size; ++I)
    {
        Dist[I] = 0x3f3f3f3f;
    }
    Dist[Node] = 0;

    std::queue<u32> Q;
    Q.push(Node);
    while (!Q.empty())
    {
        u32 Node = Q.front();
        Q.pop();

        for (u32 I = 0; I < Out[Node].size(); ++I)
        {
            if (Dist[Out[Node][I].Node] > Dist[Node] + 1)
            {
                Dist[Out[Node][I].Node] = Dist[Node] + 1;
                Q.push(Out[Node][I].Node);
            }
        }
    }
    
    return Dist;
}

std::vector<u32> graph::
DoBackwardBFS(u32 Node)
{
    std::vector<u32> Dist;
    if (!ProvideReverse)
    {
        printf("ERROR: ProvideReverse is 0 and you called DoBackwardBFS.\n");
        return Dist;
    }
    Dist.resize(Size);
    for (u32 I = 0; I < Size; ++I)
    {
        Dist[I] = 0x3f3f3f3f;
    }
    Dist[Node] = 0;

    if (!ProvideReverse)
    {
        return Dist;
    }

    std::queue<u32> Q;
    Q.push(Node);
    while (!Q.empty())
    {
        u32 Node = Q.front();
        Q.pop();

        for (u32 I = 0; I < In[Node].size(); ++I)
        {
            if (Dist[In[Node][I].Node] > Dist[Node] + 1)
            {
                Dist[In[Node][I].Node] = Dist[Node] + 1;
                Q.push(In[Node][I].Node);
            }
        }
    }
    
    return Dist;
}

std::vector<u32> graph::
DoDijkstra(u32 Node)
{
    std::vector<b32> Viz;
    std::vector<u32> Dist;
    Viz.resize(Size);
    Dist.resize(Size);
    for (u32 I = 0; I < Size; ++I)
    {
        Dist[I] = 0x3f3f3f3f;
        Viz[I] = 0;
    }
    Dist[Node] = 0;

    std::priority_queue< std::pair<i32, u32> > PQ;
    PQ.push(std::make_pair(0, Node));
    while (!PQ.empty())
    {
        u32 Node = PQ.top().second;
        PQ.pop();

        if (Viz[Node])
        {
            continue;
        }
        Viz[Node] = 1;

        for (u32 I = 0; I < Out[Node].size(); ++I)
        {
            if (Dist[Out[Node][I].Node] > Dist[Node] + Out[Node][I].Cost)
            {
                Dist[Out[Node][I].Node] = Dist[Node] + Out[Node][I].Cost;
                PQ.push(std::make_pair(-Dist[Out[Node][I].Node], Out[Node][I].Node));
            }
        }
    }
    return Dist;
}

u32 graph::
GetDistanceForwardBFS(u32 Node1, u32 Node2)
{
    std::vector<u32> Dist = DoForwardBFS(Node1);
    return Dist[Node2];
}

u32 graph::
GetDistanceBackwardBFS(u32 Node1, u32 Node2)
{
    std::vector<u32> Dist = DoBackwardBFS(Node2);
    return Dist[Node1];
}

u32 graph::
GetDistanceDijkstra(u32 Node1, u32 Node2)
{
    std::vector<u32> Dist = DoDijkstra(Node1);
    return Dist[Node2];
}
// graph.cpp

int main()
{
    printf("====================\n");

    graph Graph = {};
    Graph.StartIndex = 1;
    Graph.Read("apm.in");


    std::vector< std::pair<int, int > > Solution;
    u32 SolutionCost = 0;
    std::set<int> Set;
    std::priority_queue< std::pair<i32, std::pair<u32 ,u32> > > PQ;
    
    Set.insert(1);
    for (int I = 0; I < Graph.Out[1].size(); ++I)
    {
        PQ.push(std::make_pair(-Graph.Out[1][I].Cost,
                               std::make_pair(1, Graph.Out[1][I].Node)));
        // printf("%d %d %d\n", 1, Graph.Out[1][I].Node, -Graph.Out[1][I].Cost);
    }
    // printf("=====\n");
    // printf("%d\n", PQ.top().first);
    

    while (!PQ.empty())
    {
        u32 Cost = -PQ.top().first;
        u32 Node1 = PQ.top().second.first;
        u32 Node2 = PQ.top().second.second;
        PQ.pop();

        // for (std::set<int>::iterator it = Set.begin(); it != Set.end(); ++it)
        // {
        //     printf("%d ", *it);
        // }
        // printf("\n%d %d %d\n\n", Node1, Node2, Cost);

        if (Set.find(Node1) != Set.end() &&
            Set.find(Node2) != Set.end())
        {
            continue;
        }

        if (Set.find(Node1) == Set.end())
        {
            for (int I = 0; I < Graph.Out[Node1].size(); ++I)
            {
                PQ.push(std::make_pair(-Graph.Out[Node1][I].Cost,
                                       std::make_pair(Node1, Graph.Out[Node1][I].Node)));
            }
            Solution.push_back(std::make_pair(Node1, Node2));
            SolutionCost += Cost;
            Set.insert(Node1);
        }
        
        if (Set.find(Node2) == Set.end())
        {
            for (int I = 0; I < Graph.Out[Node2].size(); ++I)
            {
                PQ.push(std::make_pair(-Graph.Out[Node2][I].Cost,
                                       std::make_pair(Node2, Graph.Out[Node2][I].Node)));
            }
            Solution.push_back(std::make_pair(Node1, Node2));
            SolutionCost += Cost;
            Set.insert(Node2);
        }
    }

    FILE *Out = fopen("apm.out", "w");
    fprintf(Out, "%d\n", SolutionCost);
    fprintf(Out, "%d\n", Solution.size());
    for (int I = 0; I < Solution.size(); ++I)
    {
        fprintf(Out, "%d %d %d\n", Solution[I].first, Solution[I].second,
                Graph.GetCost(Solution[I].first, Solution[I].second));
    }


    return 0;
}