Cod sursa(job #1283714)

Utilizator danalex97Dan H Alexandru danalex97 Data 5 decembrie 2014 23:05:26
Problema Cuplaj maxim in graf bipartit Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 5.46 kb
#include <iostream>
#include <vector>
#include <fstream>
#include <cstring>
#include <algorithm>
using namespace std;

ifstream F("plan.in");
ofstream G("plan.out");

const int N = 265;
const int M = 1510;

/// ctcs

int n,m,mark[N],nbr;
vector<int> v[N],w[N],stack;
vector<int> ctc[N];

void go1(int x)
{
    mark[x] = 1;
    for (int i=0;i<int(v[x].size());++i)
    {
        int y = v[x][i];
        if ( mark[y] == 0 )
            go1( y );
    }
    stack.push_back(x);
}

void go2(int x)
{
    mark[x] = 1;
    ctc[nbr].push_back(x);
    for (int i=0;i<int(w[x].size());++i)
    {
        int y = w[x][i];
        if ( mark[y] == 0 )
            go2( y );
    }
}

void build_ctc()
{
    for (int i=1;i<=n;++i)
        if ( mark[i] == 0 )
            go1(i);
    memset(mark,0,sizeof(mark));
    for (int i=int(stack.size())-1;i>=0;--i)
    {
        int x = stack[i];
        if ( mark[x] == 0 )
        {
            ++nbr;
            go2(x);
        }
    }

    memset(mark,0,sizeof(mark));
}

void print_ctc()
{
    cerr<<nbr<<'\n';
    for (int i=1;i<=nbr;++i,cerr<<'\n')
        for (int j=0;j<int(ctc[i].size());++j)
            cerr<<ctc[i][j]<<' ';
}

/// end of ctcs

int my_ctc[N],in[N],out[N],root[N];
vector< pair<int,int> > ctc_edges;
vector<int> sg[N];
vector<int> bg[N];

void build_sg() // bun
{
    for (int i=1;i<=nbr;++i)
        for (int j=0;j<int(ctc[i].size());++j)
        {
            int x = ctc[i][j];
            my_ctc[x] = i;
        }
    for (int i=1;i<=n;++i)
        for (int j=0;j<int(v[i].size());++j)
        {
            int x = v[i][j];
            if ( my_ctc[i] != my_ctc[x] )
                ctc_edges.push_back( make_pair(my_ctc[i],my_ctc[x]) );
        }
    sort(ctc_edges.begin(),ctc_edges.end());
    ctc_edges.erase( unique(ctc_edges.begin(),ctc_edges.end()) , ctc_edges.end());
    for (int i=0;i<int(ctc_edges.size());++i)
    {
        int x = ctc_edges[i].first;
        int y = ctc_edges[i].second;
        out[x]++, in[y]++;
        sg[x].push_back(y);
    }
}

//

vector<int> leafs;

void find_leafs(int x)
{
    mark[x] = 1;
    for (int i=0;i<int(sg[x].size());++i)
    {
        int y = sg[x][i];
        if ( mark[y] == 0 )
            find_leafs(y);
    }
    if ( out[x] == 0 && in[x] != 0 ) // leaf
        leafs.push_back(x);
}

void build_bg() // bun
{
    vector<int> roots;
    for (int i=1;i<=nbr;++i)
        if ( in[i] == 0 && out[i] != 0 )
            roots.push_back( i );
    for (int i=0;i<int(roots.size());++i)
    {
        int x = roots[i];
        memset(mark,0,sizeof(mark));
        root[x] = 1;
        vector<int>().swap(leafs);
        find_leafs(x);
        for (int j=0;j<int(leafs.size());++j)
            bg[x].push_back( leafs[j] );
    }
}

int pl[N],pr[N],co;

int pair_up(int x)
{
    if ( pr[x] == 0 )
        return 1;
    int y = pr[x];
    if ( mark[y] == 1 )
        return 0;
    mark[y] = 1;
    for (int j=0;j<int(bg[y].size());++j)
        if ( pair_up(bg[y][j]) )
        {
            pl[y] = bg[y][j];
            pr[bg[y][j]] = y;
            return 1;
        }
    return 0;
}

void cuple_edges()
// might be problem cause of all edges togeather
{
    for (int i=1;i<=nbr;++i)
    {
        memset(mark,0,sizeof(mark));
        if ( pl[i] == 0 && root[i] )
            for (int j=0;j<int(bg[i].size());++j)
                if ( pair_up(bg[i][j]) )
                {
                    pl[i] = bg[i][j];
                    pr[bg[i][j]] = i;
                    ++co;
                    break;
                }
    }
}

vector<int> other;
vector< pair<int,int> > matching,ans;

void solve()
{
    memset(mark,0,sizeof(mark));
    for (int i=1;i<=nbr;++i)
        if ( pl[i] != 0 && mark[i] == 0 && pr[pl[i]] == i )
        {
            mark[i] = 1;
            mark[pl[i]] = 1;
            matching.push_back( make_pair( i , pl[i] ) );
        }
    for (int i=1;i<=nbr;++i)
        if ( mark[i] == 0 )
            other.push_back(i);
    for (int i=0;i<int(matching.size())-1;++i)
        ans.push_back( make_pair(matching[i].second , matching[i+1].first) );
    if ( other.size() == 0 )
    {
        ans.push_back( make_pair(matching[int(matching.size())-1].second , matching[0].first) );
    }
    else
    {
        if ( other.size() > 1 && matching.size() == 0 ) // zgood
        {
            for (int i=0;i<int(other.size())-1;++i)
                ans.push_back( make_pair(other[i],other[i+1]) );
            ans.push_back( make_pair(other[int(other.size())-1] , other[0]) );
        }
        else
            if ( other.size() != 0 && matching.size() != 0 ) // zgood
            {
                for (int i=0;i<int(other.size())-1;++i)
                    ans.push_back( make_pair(other[i],other[i+1]) );
                ans.push_back( make_pair(matching[int(matching.size())-1].second , other[0]) );
                ans.push_back( make_pair( other[int(other.size())-1] , matching[0].first ) );
            }
    }
}

int main()
{
    F>>n>>m;
    for (int i=1,x,y;i<=m;++i)
    {
        F>>x>>y;
        v[x].push_back(y);
        w[y].push_back(x);
    }

    build_ctc();
   // print_ctc();

    build_sg();
    build_bg();

    cuple_edges();

    solve();

    G<<matching.size()+other.size()<<'\n';
    for (int i=0;i<int(ans.size());++i)
        G<<ctc[ans[i].first][0]<<' '<<ctc[ans[i].second][0]<<'\n';
}