Cod sursa(job #1046518)

Utilizator OwlreeRobert Badea Owlree Data 2 decembrie 2013 23:56:42
Problema Cuplaj maxim in graf bipartit Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.82 kb
//
// Infoarena - Cuplaj Maxim In Graf Bipartit
//
// http://www.infoarena.ro/problema/cuplaj
//
// Robert M. Badea
//
// I really need to set up a convention
// for these comments tho.
//

#include <iostream> // <-- You don't need this, remove it.

#include <fstream>
#include <vector>
#include <queue>

using namespace std;

class Graph
{
private:
    vector<vector<int> >* adj;
    int vertices_n;
    
public:
    Graph(int vertices)
    {
        adj = new vector<vector<int> >(vertices + 1);
        vertices_n = vertices;
    }
    
    void add_edge(int a, int b)
    {
        if (a == 0 || b == 0)
        {
            throw 201;
        }
        
        adj -> at(a).push_back(b);
        adj -> at(b).push_back(a);
    }
    
    void add_directed_edge(int a, int b)
    {
        if (a == 0 || b == 0)
        {
            throw 201;
        }
        
        adj -> at(a).push_back(b);
    }
    
    vector<int>* adjacent_vertices(int v)
    {
        return &(adj -> at(v));
    }
    
    int size()
    {
        return vertices_n;
    }
};

class Matching
{
private:
    Graph* graph;
    vector<int>* left_to_right;
    vector<int>* right_to_left;
    vector<bool>* used;
    int matching_size;
    
    bool pairup(int vertex)
    {
        // cout << "V: " << vertex << "\n";
        if (used -> at(vertex))
        {
            return false;
        }
        
        (*used)[vertex] = true;
        
        vector<int>* adjacent_vertices = graph -> adjacent_vertices(vertex);
        int adjacent_vertices_n = (int)adjacent_vertices -> size();
        
        for (int i = 0; i < adjacent_vertices_n; ++i)
        {
            int v = vertex;
            int u = adjacent_vertices -> at(i);
            
            if (right_to_left -> at(u) == 0)
            {
                (*left_to_right)[v] = u;
                (*right_to_left)[u] = v;
                
                // cout << "Linking " << v << " and " << u << ".\n";
                
                return true;
            }
        }
        
        for (int i = 0; i < adjacent_vertices_n; ++i)
        {
            int v = vertex;
            int u = adjacent_vertices -> at(i);
            
            // cout << v << " - " << u << "\n";
            
            if (pairup(right_to_left -> at(u)))
            {
                (*left_to_right)[v] = u;
                (*right_to_left)[u] = v;
                
                // cout << "Linking " << v << " and " << u << ".\n";
                
                return true;
            }
        }
        
        return false;
    }
    
    void make_matching()
    {
        int there_is_something_to_do = true;
        
        while (there_is_something_to_do)
        {
            there_is_something_to_do = false;
            
            for (int i = 1; i <= used -> size(); ++i)
            {
                (*used)[i] = false;
            }
            
            for (int i = 1; i <= graph -> size(); ++i)
            {
                if (left_to_right -> at(i) == 0)
                {
                    there_is_something_to_do = pairup(i) || there_is_something_to_do;
                }
                // cout << there_is_something_to_do << "\n";
            }
            // cout << "Done, next one.\n";
        }
    }
    
    void make_matching_size()
    {
        int size = 0;
        
        for (int i = 0; i < left_to_right -> size(); ++i)
        {
            size += left_to_right -> at(i) != 0;
        }
        
        matching_size = size;
    }
    
public:
    Matching(Graph* _graph, int left_vertices_n, int right_vertices_n)
    {
        graph   = _graph;
        used    = new vector<bool>(graph -> size() + 1);
        
        left_to_right = new vector<int>(left_vertices_n + 1);
        right_to_left = new vector<int>(right_vertices_n + 1);
        
        make_matching();
        make_matching_size();
    }
    
    vector<int>* left()
    {
        return left_to_right;
    }
    
    vector<int>* right()
    {
        return right_to_left;
    }
    
    int size()
    {
        return matching_size;
    }
};


int main()
{
    ifstream fin    ("cuplaj.in");
    ofstream fout   ("cuplaj.out");
    
    int N, M, E;
    
    // cout << "Start!\n";
    
    fin >> N >> M >> E;
    Graph* graph = new Graph(N);
    
    for (int i = 0; i < E; ++i)
    {
        int a, b;
        fin >> a >> b;
        graph -> add_directed_edge(a, b);
    }
    
    // cout << "Getting in...\n";
    Matching* matching = new Matching(graph, N, M);
    // cout << "Got out.\n";
    
    vector<int>* left   = matching -> left();
    
    int size = matching -> size();
    
    fout << size << "\n";
    
    for (int i = 0; i < left -> size(); ++i)
    {
        if (left -> at(i) != 0)
        {
            fout << i << " " << left -> at(i) << "\n";
        }
    }
    
    fin. close();
    fout.close();
    
    return 0;
}