Cod sursa(job #2791409)

Utilizator mgntMarius B mgnt Data 30 octombrie 2021 14:28:01
Problema Andrei Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 27.83 kb
#include <fstream>                                                                                 
#include <cstddef>                                                                                 
#include <vector>                                                                                  
#include <algorithm>                                                                               
#include <numeric>                                                                                 
                                                                                                   
                                                                                                   
struct Edge {                                                                                      
                                                                                                   
    uint32_t  idm__u;                                                                              
    uint32_t  idm__v;                                                                              
                                                                                                   
    inline void assign (uint32_t  arg__a, uint32_t  arg__b) noexcept {                             
        idm__u = std::min(arg__a, arg__b);                                                         
        idm__v = std::max(arg__a, arg__b);  }                                                      
                                                                                                   
    bool operator < (Edge const  & arg__other) const noexcept {                                    
        return (idm__u == arg__other.idm__u) ? (idm__v < arg__other.idm__v)                        
                                             : (idm__u < arg__other.idm__u);  }                    
                                                                                                   
};                                                                                                 
                                                                                                   
                                                                                                   
struct Problem {                                                                                   
                                                                                                   
    size_t                 idm__n;  // idm, instance data member                                   
    size_t                 idm__m;                                                                 
    size_t                 idm__h;                                                                 
    size_t                 idm__k;                                                                 
    std::vector<Edge>      idm__E;                                                                 
    std::vector<size_t>    idm__J;                                                                 
    std::vector<uint32_t>  idm__A;                                                                 
    std::vector<uint32_t>  idm__Q;                                                                 
    std::vector<uint8_t>   idm__P;                                                                 
                                                                                                   
    Problem (void) {                                                                               
        idm__n = 0;  idm__m = 0;  idm__k = 0;  idm__k = 0;  }                                      
                                                                                                   
};                                                                                                 
                                                                                                   
                                                                                                   
void dfs__group_nodes (Problem  & arg__problem, uint32_t  arg__q, size_t  arg__x) {                
    /// The DFS grouping nodes connected by purple edges.                                          
    arg__problem.idm__Q.at(arg__x) = arg__q;                                                       
    size_t  as__begin = arg__problem.idm__J.at(arg__x + 0); // as, automatic storage (duration)    
    size_t  as__end   = arg__problem.idm__J.at(arg__x + 1);                                        
    size_t  as__i = 0;                                                                             
    for (as__i = as__begin; as__end > as__i; ++as__i) {                                            
        if (arg__problem.idm__Q.at(arg__problem.idm__A.at(as__i)) != arg__q) {                     
            dfs__group_nodes(arg__problem, arg__q, arg__problem.idm__A.at(as__i));  }}             
}                                                                                                  
                                                                                                   
void dfs__bipartition (Problem  & arg__problem, uint8_t  arg__p, size_t  arg__x) {                 
    /// The DFS partitioning nodes in the two partitions of the bipartite graph.                   
    arg__problem.idm__P.at(arg__x) = arg__p;                                                       
    size_t  as__begin = arg__problem.idm__J.at(arg__x + 0);                                        
    size_t  as__end   = arg__problem.idm__J.at(arg__x + 1);                                        
    size_t  as__i = 0;                                                                             
    for (as__i = as__begin; as__end > as__i; ++as__i) {                                            
        if (arg__problem.idm__P.at(arg__problem.idm__A.at(as__i)) == arg__p) {                     
            throw std::invalid_argument("Invalid edge!");  }                                       
        if (arg__problem.idm__P.at(arg__problem.idm__A.at(as__i)) == 2) {                          
            dfs__bipartition(arg__problem, 1 - arg__p, arg__problem.idm__A.at(as__i));  }}         
}                                                                                                  
                                                                                                   
void build_adjacencies (Problem  & arg__problem, size_t  arg__begin, size_t  arg__end) {           
                                                                                                   
    // Sort edges;  this is supports filtering out duplicated edges.                               
    std::vector<Edge>  & as__E = arg__problem.idm__E;                                              
    std::sort(as__E.begin() + arg__begin, as__E.begin() + arg__end);                               
                                                                                                   
    // Filter out duplicate edges.                                                                 
    size_t  as__end2 = arg__begin;                                                                 
    size_t  as__i = 0;                                                                             
    for (as__i = arg__begin + 1; arg__end > as__i; ++as__i) {                                      
        if (as__E.at(as__end2) < as__E.at(as__i)) {                                                
            if ((as__end2 + 1) != as__i) {                                                         
                as__E.at(as__end2 + 1) = as__E.at(as__i);  }                                       
            ++as__end2;  }}                                                                        
    if (as__end2 < arg__end) {                                                                     
        ++as__end2;  }                                                                             
                                                                                                   
    // Count how many edges are adjacent with each node.                                           
    size_t  const as__n = arg__problem.idm__n;                                                     
    std::vector<size_t>  & as__J = arg__problem.idm__J;                                            
    std::fill(as__J.begin(), as__J.begin() + as__n, 0);                                            
    for (as__i = arg__begin; as__end2 > as__i; ++as__i) {                                          
        as__J.at(as__E.at(as__i).idm__u) += 1;                                                     
        as__J.at(as__E.at(as__i).idm__v) += 1;  }                                                  
                                                                                                   
    // Determine from which index to store neighbours, for each node.                              
    size_t  as__pos = 0;  size_t  as__count = 0;                                                   
    for (as__i = 0; as__n > as__i; ++ as__i) {                                                     
        as__count = as__J.at(as__i);  as__J.at(as__i) = as__pos;  as__pos += as__count;  }         
                                                                                                   
    // Put the neighbours in the adjacency lists.                                                  
    std::vector<uint32_t>  & as__A = arg__problem.idm__A;                                          
    for (as__i = arg__begin; as__end2 > as__i; ++as__i) {                                          
        as__A.at(as__J.at(as__E.at(as__i).idm__u)) = as__E.at(as__i).idm__v;                       
        as__A.at(as__J.at(as__E.at(as__i).idm__v)) = as__E.at(as__i).idm__u;                       
        as__J.at(as__E.at(as__i).idm__u) += 1;                                                     
        as__J.at(as__E.at(as__i).idm__v) += 1;  }                                                  
                                                                                                   
    // Count how many edges are adjacent with each node.                                           
    std::fill(as__J.begin(), as__J.begin() + as__n, 0);                                            
    for (as__i = arg__begin; as__end2 > as__i; ++as__i) {                                          
        as__J.at(as__E.at(as__i).idm__u) += 1;                                                     
        as__J.at(as__E.at(as__i).idm__v) += 1;  }                                                  
                                                                                                   
    // Determine from which index the neighbours were stored, for each node.                       
    as__pos = 0;  as__count = 0;                                                                   
    for (as__i = 0; as__n > as__i; ++ as__i) {                                                     
        as__count = as__J.at(as__i);  as__J.at(as__i) = as__pos;  as__pos += as__count;  }         
                                                                                                   
    // Also determine for the 'end' node, a sentinel.                                              
    as__J.at(as__n) = as__pos;                                                                     
}                                                                                                  
                                                                                                   
void group_the_nodes_connected_by_purple_edges (Problem  & arg__problem) {                         
    ///  It groups together with all neighbours (by purple edges), each not yet grouped node.      
                                                                                                   
    size_t  const as__m = arg__problem.idm__m;                                                     
    size_t  const as__k = arg__problem.idm__k;                                                     
    build_adjacencies(arg__problem, as__m - as__k, as__m);                                         
                                                                                                   
    size_t  const as__n = arg__problem.idm__n;                                                     
    std::vector<uint32_t>  & as__Q = arg__problem.idm__Q;                                          
    uint32_t  as__r = 0;  size_t  as__i = 0;                                                       
                                                                                                   
    for (as__i = as__r = 0; as__n > as__i; ++as__i, ++as__r) {                                     
        as__Q.at(as__i) = as__r;  }                                                                
                                                                                                   
    for (as__i = as__r = 0; as__n > as__i; ++as__i, ++as__r) {                                     
        if (as__Q.at(as__i) == as__r) {                                                            
            dfs__group_nodes(arg__problem, as__r, as__i);  }}                                      
                                                                                                   
}                                                                                                  
                                                                                                   
void relabel_the_white_and_red_edges (Problem  & arg__problem) {                                   
    /// It relabels white and red edges accounting how nodes were grouped on their purple edges.   
                                                                                                   
    std::vector<uint32_t>  & as__Q = arg__problem.idm__Q;                                          
    std::vector<Edge>  & as__E = arg__problem.idm__E;                                              
    size_t  const as__h = arg__problem.idm__h;  size_t  as__i = 0;                                 
    for (as__i = 0; as__h > as__i; ++as__i) {                                                      
        as__E.at(as__i).idm__u = as__Q.at(as__E.at(as__i).idm__u);                                 
        as__E.at(as__i).idm__v = as__Q.at(as__E.at(as__i).idm__v);                                 
        if (as__E.at(as__i).idm__u == as__E.at(as__i).idm__v) {                                    
            throw std::invalid_argument("Invalid edge.");  }}                                      
                                                                                                   
}                                                                                                  
                                                                                                   
void check_that_the_simplified_graph_is_bipartite (Problem  & arg__problem) {                      
    /// It checks that the simplified graph is bipartite, by building its partitions A and B.      
                                                                                                   
    build_adjacencies(arg__problem, 0, arg__problem.idm__h);                                       
                                                                                                   
    std::vector<uint32_t>   & as__Q = arg__problem.idm__Q;                                         
    std::vector<uint8_t>    & as__P = arg__problem.idm__P;                                         
    size_t  const as__n = arg__problem.idm__n;                                                     
    size_t  as__i = 0;  uint32_t  as__r = 0;                                                       
                                                                                                   
    for (as__i = 0, as__r = 0; as__n > as__i; ++as__i, ++as__r) {                                  
        as__P.at(as__i) = (as__Q.at(as__i) == as__r) ? 2 : 3;  }                                   
                                                                                                   
    for (as__i = 0; as__n > as__i; ++as__i) {                                                      
        if (as__P.at(as__i) == 2) {                                                                
            dfs__bipartition (arg__problem, 0, as__i);  }}                                         
                                                                                                   
}                                                                                                  
                                                                                                   
void color_each_group_of_nodes_connected_by_purple_edges (Problem  & arg__problem) {               
    /// Puts the color to all nodes in the group, for each node in the simplified graph.           
                                                                                                   
    std::vector<uint32_t>   & as__Q = arg__problem.idm__Q;                                         
    std::vector<uint8_t>    & as__P = arg__problem.idm__P;                                         
    size_t  const as__n = arg__problem.idm__n;                                                     
    size_t  as__i = 0;  uint32_t  as__r = 0;                                                       
                                                                                                   
    for (as__i = 0, as__r = 0; as__n > as__i; ++as__i, ++as__r) {                                  
        if (as__Q.at(as__i) != as__r) {                                                            
            as__P.at(as__i) = as__P.at(as__Q.at(as__i));  }}                                       
                                                                                                   
}                                                                                                  
                                                                                                   
void read_the_graph (Problem  & arg__problem) {                                                    
                                                                                                   
    size_t  as__n = 0;  size_t  as__m = 0;                                                         
    std::ifstream  as__is("andrei.in");                                                            
                                                                                                   
    as__is >> as__n >> as__m;                                                                      
                                                                                                   
    if ((1 > as__n) || (100000 < as__n) || (1 > as__m) || (200000 < as__m)) {                      
        throw std::invalid_argument("Invalid graph size.");  }                                     
                                                                                                   
    if (std::numeric_limits<size_t>::max() - 1 < as__n) {                                          
        throw std::runtime_error("Implementation limit.  As if.");  }                              
                                                                                                   
    if (std::numeric_limits<size_t>::max() - as__m < as__m) {                                      
        throw std::runtime_error("Implementation limit.  As if.");  }                              
                                                                                                   
    std::vector<uint8_t>   as__P(as__n);                                                           
    std::vector<uint32_t>  as__Q(as__n);                                                           
    std::vector<size_t>    as__J(as__n + 1);                                                       
    std::vector<uint32_t>  as__A(as__m + as__m);                                                   
    std::vector<Edge>  as__E(as__m);                                                               
    size_t  as__i = 0;  uint32_t  as__a = 0;  uint32_t  as__b = 0;  uint32_t  as__c = 0;           
    size_t  as__h = 0;  size_t    as__k = 0;                                                       
                                                                                                   
    for (as__i = 0; as__n > as__i; ++as__i) {                                                      
                                                                                                   
        as__is >> as__a >> as__b >> as__c;                                                         
                                                                                                   
        if ((1 > as__a) || (as__n < as__a) || (1 > as__b) || (as__n < as__b) || (2 < as__c)) {     
            throw std::invalid_argument("Invalid edge.");  }                                       
                                                                                                   
        if ((as__a == as__b) && ((as__c == 0) || (as__c == 1))) {                                  
            throw std::invalid_argument("Invalid edge.");  }                                       
                                                                                                   
        --as__a; --as__b;                                                                          
                                                                                                   
        if (2 == as__c) {                                                                          
            /*  Purple.  */                                                                        
            if (as__a != as__b) {                                                                  
                as__E.at((as__m - 1) - as__k).assign(as__a, as__b);  ++as__k;  }}                  
        else {                                                                                     
            /*  White or Red.  */  as__E.at(as__h).assign(as__a, as__b);  ++as__h;  }}             
                                                                                                   
    // Okay!                                                                                       
    arg__problem.idm__n = as__n;                                                                   
    arg__problem.idm__m = as__m;                                                                   
    arg__problem.idm__h = as__h;                                                                   
    arg__problem.idm__k = as__k;                                                                   
    arg__problem.idm__E.swap(as__E);                                                               
    arg__problem.idm__J.swap(as__J);                                                               
    arg__problem.idm__A.swap(as__A);                                                               
    arg__problem.idm__Q.swap(as__Q);                                                               
    arg__problem.idm__P.swap(as__P);                                                               
}                                                                                                  
                                                                                                   
void partition_the_nodes (Problem  & arg__problem) {                                               
    group_the_nodes_connected_by_purple_edges (arg__problem);                                      
    relabel_the_white_and_red_edges (arg__problem);                                                
    check_that_the_simplified_graph_is_bipartite (arg__problem);                                   
    color_each_group_of_nodes_connected_by_purple_edges (arg__problem);                            
}                                                                                                  
                                                                                                   
void write_the_partition (Problem  & arg__problem) {                                               
                                                                                                   
    std::ofstream  as__os("andrei.out");                                                           
                                                                                                   
    std::vector<uint8_t> const  & as__P = arg__problem.idm__P;                                     
    size_t const  as__n = arg__problem.idm__n;  size_t  as__i = 0;                                 
                                                                                                   
    as__os << static_cast<uint32_t>(as__P.at(0));                                                  
    for (as__i = 1; as__n > as__i; ++as__i) {                                                      
        as__os << ' ' << static_cast<uint32_t>(as__P.at(as__i));  }                                
    as__os << '\n';                                                                                
}                                                                                                  
                                                                                                   
void demo (void) {                                                                                 
                                                                                                   
    Problem  as__problem;                                                                          
    read_the_graph (as__problem);                                                                  
    partition_the_nodes (as__problem);                                                             
    write_the_partition (as__problem);                                                             
                                                                                                   
}                                                                                                  
                                                                                                   
int main (void) {                                                                                  
                                                                                                   
    int  status = 19;                                                                              
                                                                                                   
    try {                                                                                          
        demo();                                                                                    
        status = 0;  }                                                                             
    catch ( std::invalid_argument const  & exc ) {                                                 
        (void) exc;                                                                                
        status = 17;  }                                                                            
    catch ( ... ) {                                                                                
        status = 19;  }                                                                            
                                                                                                   
    return status;                                                                                 
}