Cod sursa(job #987338)

Utilizator tzipleatudTudor Tiplea tzipleatud Data 20 august 2013 14:43:47
Problema Nowhere-zero Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.52 kb
#include <fstream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <cstring>
#include <cmath>

#define NM 100010
#define MM 400010
#define x first
#define y second

using namespace std;

ifstream f("nowhere-zero.in");
ofstream g("nowhere-zero.out");

typedef pair<int, int> PI;
typedef pair<double, double> PD;

int N, M;
vector<int> G[NM];
PD Points[NM], Center;

map<PI, int> WallCode, WallValue;
map<PI, bool> WallVisited;
int WallZones[MM];

int NoZones;
set<int> GZones[MM];
bool Exists[MM];
int Degree[MM], ZoneColor[MM];

bool CompareByTan (int a, int b)
{
    return atan2(Points[a].y-Center.y, Points[a].x-Center.x) < atan2(Points[b].y-Center.y, Points[b].x-Center.x);
}

void Read ()
{
    f >> N >> M;
    for (int i=1; i<=N; i++)
        f >> Points[i].x >> Points[i].y;

    for (int i=1; i<=M; i++)
    {
        int a, b;
        f >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);

        WallCode[make_pair(a, b)]=M;
        WallCode[make_pair(b, a)]=i+M;
    }

    f.close();
}

void SortG ()
{
    for (int i=1; i<=N; i++)
    {
        Center=Points[i];
        sort(G[i].begin(), G[i].end(), CompareByTan);
    }
}

int SearchPosition (int center, int next)
{
    int P=0, U=G[center].size()-1, M, ANS=-1;
    int vec;

    double tan = atan2(Points[next].y-Points[center].y, Points[next].x-Points[center].x);

    while (P<=U)
    {
        M=(P+U)/2;
        vec=G[center][M];

        if (atan2(Points[vec].y-Points[center].y, Points[vec].x-Points[center].y) <= vec)
        {
            ANS=M;
            P=M+1;
        }
        else
            U=M-1;
    }

    return ANS;
}

bool GoOnWalls (int source, int father, int node)
{
    if (node==source)
    {
        ++NoZones;
        return 1;
    }

    int position=SearchPosition(node, father);
    bool found = 0;
    int j, size=G[node].size();

    for (j=(position+1)%size; j!=father; j=(j+1)%size)
        if (!WallVisited[make_pair(node, j)])
        {
            found=1;
            break;
        }

    if (found==0) return 0;

    WallVisited[make_pair(node, j)]=1;
    found = GoOnWalls(source, node, j);

    if (found==1)
    {
        WallZones[WallCode[make_pair(node, j)]]=NoZones;
        return 1;
    }

    WallVisited[make_pair(node, j)]=0;
    return 0;
}

void BuildZones ()
{
    int i;
    vector<int>::iterator it;

    for (i=1; i<=N; i++)
        for (it=G[i].begin(); it!=G[i].end(); ++it)
            if (!WallVisited[make_pair(i, *it)])
            {
                WallVisited[make_pair(i, *it)]=1;
                bool ok=GoOnWalls(i, i, *it);
                int code=WallCode[make_pair(i, *it)];

                if (ok)
                    WallZones[code]=NoZones;
                else
                    WallVisited[make_pair(i, *it)]=0;
            }
}

void BuildGraph ()
{
    int i;
    vector<int>::iterator it;

    for (i=1; i<=N; i++)
        for (it=G[i].begin(); it!=G[i].end(); ++it)
            if (i<*it)
            {
                int zone1 = WallZones[WallCode[make_pair(i, *it)]];
                int zone2 = WallZones[WallCode[make_pair(*it, i)]];

                if (zone1!=0 && zone2!=0)
                {
                    GZones[zone1].insert(zone2);
                    GZones[zone2].insert(zone1);
                }
            }
}

void ColorZones ()
{
    stack<int> MyStack;
    set<PI> MySet;
    set<PI>::iterator set1, set2;
    set<int>::iterator it;

    for (int i=1; i<=NoZones; i++)
    {
        Exists[i]=1;
        Degree[i]=GZones[i].size();

        MySet.insert(make_pair(Degree[i], i));
    }

    while (!MySet.empty())
    {
        set1=MySet.begin();
        int node = set1->second;
        MySet.erase(set1);

        if (Exists[node]==0) continue;

        MyStack.push(node);
        Exists[node]=0;

        for (it=GZones[node].begin(); it!=GZones[node].end(); ++it)
            if (Exists[*it])
            {
                set1=MySet.find(make_pair(Degree[*it], *it));
                if (set1==MySet.end()) continue;

                MySet.erase(set1);
                Degree[*it]--;
                MySet.insert(make_pair(Degree[*it], *it));
            }
    }

    bool Marked[7];
    while (!MyStack.empty())
    {
        int node = MyStack.top();
        MyStack.pop();

        for (int i=0; i<=6; i++)
            Marked[i]=0;

        for (it=GZones[node].begin(); it!=GZones[node].end(); ++it)
            Marked[ZoneColor[*it]]=1;

        for (int i=1; i<=6; i++)
            if (Marked[i]==0)
            {
                ZoneColor[node]=i;
                break;
            }
    }
}

void Print ()
{
    int i;
    vector<int>::iterator it;

    for (i=1; i<=N; i++)
        for (it=G[i].begin(); it!=G[i].end(); ++it)
            if (i<*it)
            {
                int zone1 = WallZones[WallCode[make_pair(i, *it)]];
                int zone2 = WallZones[WallCode[make_pair(*it, i)]];

                if (ZoneColor[zone1]>ZoneColor[zone2])
                    g << i << ' ' << (*it) << ' ' << (ZoneColor[zone1] - ZoneColor[zone2]) << '\n';
                else
                    g << (*it) << ' ' << i << ' ' << (ZoneColor[zone2] - ZoneColor[zone1]) << '\n';
            }

    g.close();
}

int main ()
{
    Read();
    SortG();
    BuildZones();
    BuildGraph();
    ColorZones();
    Print();

    return 0;
}