Cod sursa(job #2820158)

Utilizator Radu_FilipescuFilipescu Radu Radu_Filipescu Data 19 decembrie 2021 22:44:41
Problema Cuplaj maxim in graf bipartit Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 12.37 kb
#include <bits/stdc++.h>

using namespace std;

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

int match[10005], dist[10005];

class graph {
private:
    static const int INF = 2000'000'000;
    int N;                                          /// number of nodes
    int t = 0;                                      /// auxiliary variable, for different needs
    vector< vector<int> > ad;
    vector< vector<int> > reverseAd;
    vector< vector<int> > cost;
    //vector<int> dist;
    vector<int> low;
    vector<int> parent;
    vector<int> aux;                                /// auxiliary vector, for different needs
    vector<pair<int,int> > criticalEdges;
    int conexComponents;                            /// requires DFSTraversal to set the value
    vector< vector<int> > adMat;
    vector< vector<int> > flowMat;
    vector< vector<int> > capMat;

    void Dfs( int node ) {
        aux.push_back( node );
        dist[node] = 1;

        for( int i = 0; i < ad[node].size(); ++i ) {
            int w = ad[node][i];

            if( dist[w] == 0 )
                Dfs( w );
        }
    }
    void Dfs2( int node, int parent, vector<vector<int> > &_solution ) {
        dist[node] = low[node] = ++t;
        aux.push_back( node );

        for( int i = 0; i < ad[node].size(); ++i ) {
           int w = ad[node][i];

           if( w == parent ) continue;

           if( dist[w] > 0 ) low[node] = min( low[node], dist[w] );
           else {
              Dfs2( w, node, _solution );
              low[node] = min( low[node], low[w] );

              if( low[w] >= dist[node] ) {
                 if( low[w] > dist[node] )
                 criticalEdges.push_back( { w, node } );

                 vector <int> tmp;

                 while( aux.back() != w ) {
                    tmp.push_back( aux.back() );
                    aux.pop_back();
                 }
                 tmp.push_back( aux.back() );
                 aux.pop_back();

                 tmp.push_back( node );
                 _solution.push_back( tmp );
              }
           }
        }
    }
    void Dfs3( int node ) {
        dist[node] = 1;

        for( int i = 0; i < ad[node].size(); ++i ) {
            int w = ad[node][i];

            if( dist[w] == 0 )
                Dfs3( w );
        }

        aux.push_back( node );
    }
    void Dfs4( int node, vector<int> &v ) {
        dist[node] = 1;
        v.push_back( node );

        for( int i = 0; i < reverseAd[node].size(); ++i ) {
            int w = reverseAd[node][i];

            if( dist[w] == 0 )
                Dfs4( w, v );
        }
    }
    bool Dfs5( int nod ) {
        if( nod == 0 ) return true;

        int w;
        for( int i = 0; i < ad[nod].size(); ++i ) {
            w = ad[nod][i];

            if( dist[ match[w] ] == dist[nod] + 1 && Dfs5( match[w] ) ) {
                match[nod] = w;
                match[w] = nod;

                return true;
            }
        }

        dist[nod] = INF;

        return false;
    }
    bool isReachable() {
        for( int i = 1; i <= N; ++i )
            dist[i] = 0;

        deque <int> Q;

        dist[1] = 1;
        Q.push_back( 1 );

        int u, w;

        while( !Q.empty() ) {
            u = Q.front();
            Q.pop_front();

            if( u == N ) continue;

            for( int i = 0; i < ad[u].size(); ++i ) {
                w = ad[u][i];

                if( !dist[w] && capMat[u][w] > flowMat[u][w] ) {
                    dist[w] = 1;
                    Q.push_back( w );

                    parent[w] = u;
                }
            }
        }

        return dist[N];
    }
    bool Bfs() {
        deque <int> Q;

        dist[0] = INF;

        for( int i = 1; i <= N; ++i )
            if( match[i] == 0 ) {
                Q.push_back( i );
                dist[i] = 0;
            }
            else dist[i] = INF;

        int u, w;

        while( !Q.empty() ) {
            u = Q.front();
            Q.pop_front();

            if( u == 0 ) continue;

            for( int i = 0; i < ad[u].size(); ++i ) {
                w = ad[u][i];

                if( dist[ match[w] ] == INF ) {
                    dist[ match[w] ] = dist[u] + 1;
                    Q.push_back( match[w] );
                }
            }
        }

        return ( dist[0] < INF );
    }
public:
    graph( int n ) {
        N = n;
        ad.resize( n + 1 );
        //cost.resize( n + 1 );
        //dist.resize( n + 1 );
        //low.resize( n + 1 );
        //reverseAd.resize( n + 1 );
        //parent.resize( n + 1 );

        //vector <int> tmp(n + 1);
        //for( int i = 0; i <= n; i++ ) {
        //    adMat.push_back( tmp );
        //    flowMat.push_back( tmp );
        //    capMat.push_back( tmp );
        //}
    }
    void changeN( int n ) {
        N = n;
        ad.resize( n + 1 );
        cost.resize( n + 1 );
        //dist.resize( n + 1 );
        low.resize( n + 1 );
        reverseAd.resize( n + 1 );
        parent.resize( n + 1 );

        vector <int> tmp(n + 1);
        for( int i = 0; i <= n; i++ ) {
            adMat.push_back( tmp );
            flowMat.push_back( tmp );
            capMat.push_back( tmp );
        }
    }
    int getN() { return N; }
    void addEdge( int x, int y, bool directed = false, int c = 0 ) {
        ad[x].push_back(y);
        //cost[x].push_back(c);

        //reverseAd[y].push_back(x);

        if( !directed ) {
            ad[y].push_back(x);
            //cost[y].push_back(c);
            //reverseAd[x].push_back(y);
        }

        //adMat[x][y] = c;
        //if( !directed ) adMat[y][x] = c;
    }
    void addFlowEdge( int x, int y, int cap ) {
        capMat[x][y] = capMat[y][x] = cap;
    }
    void setAdMat( vector<vector<int> > mat ) {
        adMat = mat;
    }
    vector <int> dfsTraversal() {
        aux.clear();
        conexComponents = 0;

        for( int i = 1; i <= N; ++i )
            dist[i] = 0;

        for( int i = 1; i <= N; i++ )
            if( dist[i] == 0 ) {
                Dfs( i );
                ++conexComponents;
            }

        return aux;
    }
    void bfsTraversal( int source ) {
        queue<int> Q;

        for( int i = 0; i <= N; i++ )
            dist[i] = 0;

        dist[source] = 1;
        Q.push( source );

        while( !Q.empty() ) {
            int u = Q.front();
            Q.pop();

            for( int i = 0; i < ad[u].size(); ++i ) {
                int w = ad[u][i];

                if( dist[w] == 0 ) {
                    dist[w] = dist[u] + 1;
                    Q.push( w );
                }
            }
        }
    }
    int graphDiameter() {
        bfsTraversal( 1 );

        int maxDist = -1, maxNode;

        for( int i = 1; i <= N; ++i )
            if( dist[i] > maxDist ) {
                maxDist = dist[i];
                maxNode = i;
            }

        bfsTraversal( maxNode );

        maxDist = -1;
        for( int i = 1; i <= N; ++i )
            maxDist = max( maxDist, dist[i] );

        return maxDist;
    }
    vector<int>getTopologicalSort() {
        aux.clear();
        for( int i = 1; i <= N; i++ )
            dist[i] = 0;

        for( int i = 1; i <= N; i++ )
            if( dist[i] == 0 )
                Dfs3( i );

        return aux;
    }
    vector<vector<int> > getStronglyConnectedComponents() {
        vector<vector<int> > sol;
        vector<int> topologicalSort = getTopologicalSort();

        for( int i = 0; i <= N; i++ )
            dist[i] = 0;


        for( int i = topologicalSort.size() - 1; i >= 0; --i ) {
            int node = topologicalSort[i];

            if( dist[node] ) continue;

            vector<int> tmp;

            Dfs4( node, tmp );

            sol.push_back( tmp );
        }

        return sol;
    }
    vector<vector<int> > getBiconnectedComponents() {
        vector<vector<int> > sol;

        for( int i = 1; i <= N; ++i )
            if( dist[i] == 0 )
                Dfs2( i, 0, sol );

        return sol;
    }
    int getConexComponents() {                      /// requires DFS to be called first
        return conexComponents;
    }
    //vector <int> getDistances() {                   /// requires BFS to be called first
    //    return dist;
    //}
    vector <pair<int,int> > getCriticalEdges() {    /// requires getBiconnectedComps to be called first
        return criticalEdges;
    }
    int maxFlow() {
        int totFlow = 0;
        int currentFlow;

        while( isReachable() ) {
            for( int i = 0; i < ad[N].size(); ++i ) {
                int aux = ad[N][i];

                if( capMat[aux][N] == flowMat[aux][N] || !dist[aux] ) continue;

                currentFlow = INF;

                parent[N] = aux;

                for( int i = N; i != 1; i = parent[i] )
                    currentFlow = min( currentFlow, capMat[ parent[i] ][i] - flowMat[ parent[i]][i] );

                for( int i = N; i != 1; i = parent[i] ) {
                    flowMat[ parent[i] ][i] += currentFlow;
                    flowMat[i][ parent[i] ] -= currentFlow;
                }

                totFlow += currentFlow;
            }
        }

        return totFlow;
    }
    static bool HavelHakimiUtillity( vector<int> degree ) {
        while( !degree.empty() ) {
            sort( degree.begin(), degree.end() );

            if( degree.back() < 0 )
                return false;

            if( degree.back() > degree.size() - 1 )
                return false;

            for( int i = 1; i <= degree.back(); ++i )
                degree[degree.size() - i - 1]--;

            degree.pop_back();
        }

        return true;
    }
    vector <vector<int> > royFloyd() {
        vector< vector<int> > dist;

        for( int i = 0; i <= N; ++i ) {
            vector<int> tmp;
            tmp.resize( N + 1 );

            dist.push_back( tmp );
        }

        for( int i = 1; i <= N; ++i )
            for( int j = 1; j <= N; ++j )
                dist[i][j] = INF;

        for( int i = 1; i <= N; ++i )
            for( int j = 1; j <= N; ++j )
                if( adMat[i][j] ) dist[i][j] = adMat[i][j];

        for( int k = 1; k <= N; ++k )
            for( int i = 1; i <= N; ++i )
                for( int j = 1; j <= N; ++j )
                    if( i != j )
                        if( dist[i][k] < INF && dist[k][j] < INF && dist[i][j] > dist[i][k] + dist[k][j] )
                            dist[i][j] = dist[i][k] + dist[k][j];

        return dist;
    }
    bool isEulerian() {
        for( int i = 0; i < ad.size(); ++i )
            if( ad[i].size() % 2 )
                return false;

        return true;
    }
    vector <int> eulerCycle() {
        vector<int> ans;

        int w, nod;
        bool found;

        deque <int> S;
        S.push_back( 1 );

        while( !S.empty() ) {
            nod = S.back();
            S.pop_back();

            found = false;

            while( !ad[nod].empty() && !found ) {
                w = ad[nod].back();
                ad[nod].pop_back();

                if( w == -1 ) continue;

                S.push_back( nod );
                S.push_back( w );

                for( int i = 0; i < ad[w].size(); ++i )
                    if( ad[w][i] == nod ) {
                        ad[w][i] = -1;
                        break;
                    }

                found = true;
            }

            if( found ) continue;
            else ans.push_back( nod );
        }

        return ans;
    }
    int maximalMatching() {
        int matching = 0;

        while( Bfs() )
        for( int i = 1; i <= N; ++i )
            if( match[i] == 0 && Dfs5( i ) )
                ++matching;

        return matching;
    }
};


int main()
{
    int n, m, nrEdges;
    int x, y;

    fin >> n >> m >> nrEdges;

    graph G(n + m);


    for( int i = 1; i <= nrEdges; ++i ) {
        fin >> x >> y;

        G.addEdge( x, n + y );
    }

    fout << G.maximalMatching() << '\n';

    for( int i = 1; i <= n; ++i )
        if( match[i] != 0 )
            fout << i << ' ' << match[i] - n << '\n';

    return 0;
}