Cod sursa(job #1260806)

Utilizator andreiiiiPopa Andrei andreiiii Data 11 noiembrie 2014 16:47:30
Problema Nowhere-zero Scor 30
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.14 kb
#include <algorithm>
#include <bitset>
#include <cstdio>
#include <cmath>
#include <vector>

using namespace std;

const int Nmax = 100005, Mmax = Nmax * 3;

struct Point {
    double x, y;
};

Point points[Nmax];
pair<int, int> edges[Mmax];
int Capacity[Mmax];

vector<int> G[Nmax], Gz[Mmax];
int Zone[Mmax][2], Color[Mmax];

int deg[Mmax];
bitset<Mmax> used;

double crossProduct(const Point &o, const Point &a, const Point &b) {
    return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
}

double dotProduct(const Point &o, const Point &a, const Point &b) {
    return (a.x - o.x) * (b.x - o.x) + (a.y - o.y) * (b.y - o.y);
}

double dist(const Point &a, const Point &b) {
    return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
}

double cosAngle(const Point &o, const Point &a, const Point &b) {
    return dotProduct(o, a, b) / (dist(o, a) * dist(o, b));
}

double getSign(const double d) {
    return d < 0 ? -1: 1;
}

int getZones(int N, int M) {
    int czones = 0;
    for (int i = 1; i <= M; ++i) {
        for (int j = 0; j < 2; ++j) {
            if (Zone[i][j]) continue;

            czones++;
            int goodSign = j == 0 ? -1: 1;
            for (int k = i, lastNode = edges[i].second, lastOther = edges[i].first; ;) {
                if (Zone[k][lastNode == edges[k].second ? j: (j ^ 1)]) break;

                Zone[k][lastNode == edges[k].second ? j: (j ^ 1)] = czones;
                int goodEdge = 0;
                double goodAngle = 2;

                int mulSign = -1, rGoodSign = -goodSign;
                for (int p: G[lastNode]) {
                    if (p != k) {
                        int other = edges[p].first == lastNode ? edges[p].second: edges[p].first;
                        int sign = getSign(crossProduct(points[lastOther], points[lastNode], points[other]));
                        if (sign == goodSign) {
                            mulSign = 1;
                            rGoodSign *= -1;
                            goodAngle *= -1;
                            break;
                        }
                    }
                }
                for (int p: G[lastNode]) {
                    if (p != k) {
                        int other = edges[p].first == lastNode ? edges[p].second: edges[p].first;
                        int sign = getSign(crossProduct(points[lastOther], points[lastNode], points[other]));
                        double cosAng = cosAngle(points[lastNode], points[lastOther], points[other]);
                        if (sign == rGoodSign && cosAng * mulSign > goodAngle * mulSign) {
                            goodEdge = p;
                            goodAngle = cosAng;
                        }
                    }
                }

                int node = edges[goodEdge].first == lastNode ? edges[goodEdge].second: edges[goodEdge].first;
                int other = (edges[goodEdge].first ^ edges[goodEdge].second ^ node);

                k = goodEdge;
                lastNode = node;
                lastOther = other;
            }
        }
    }

    return czones;
}

void buildZoneGraph(int N, int M) {
    for (int i = 1; i <= M; ++i) {
        Gz[Zone[i][0]].push_back(Zone[i][1]);
        Gz[Zone[i][1]].push_back(Zone[i][0]);
    }
}

void colorNewGraph(int N) {
    vector<int> order;
    order.reserve(N);
    for (int i = 1; i <= N; ++i) {
        deg[i] = Gz[i].size();
        if (deg[i] < 6) {
            order.push_back(i);
            used[i] = 1;
        }
    }

    for (int i = 0; i < N; ++i) {
        int node = order[i];

        for (int p: Gz[node]) {
            deg[p]--;
            if (!used[p] && deg[p] < 6) {
                used[p] = 1;
                order.push_back(p);
            }
        }
    }
    reverse(order.begin(), order.end());

    for (int node: order) {
        bool usedCol[7];
        for (int i = 0; i < 7; ++i) usedCol[i] = 0;
        for (int p: Gz[node])
            usedCol[Color[p]] = 1;

        for (int i = 1; ; ++i) {
            if (!usedCol[i]) {
                Color[node] = i;
                break;
            }
        }
    }
}

void setEdges(int N, int M) {
    for (int i = 1; i <= M; ++i) {
        Capacity[i] = Color[Zone[i][1]] - Color[Zone[i][0]];
        if (Capacity[i] < 0) {
            Capacity[i] = -Capacity[i];
            swap(edges[i].first, edges[i].second);
        }
    }
}

void writeAnswer(int N, int M) {
    for (int i = 1; i <= M; ++i)
        printf("%d %d %d\n", edges[i].first, edges[i].second, Capacity[i]);
}

int main()
{
    freopen("nowhere-zero.in", "r", stdin);
    freopen("nowhere-zero.out", "w", stdout);

    int N, M;
    scanf("%d%d", &N, &M);

    for (int i = 1; i <= N; ++i)
        scanf("%lf%lf", &points[i].x, &points[i].y);

    for (int i = 1; i <= M; ++i) {
        scanf("%d%d", &edges[i].first, &edges[i].second);
        G[edges[i].first].push_back(i);
        G[edges[i].second].push_back(i);
    }

    int czones = getZones(N, M);
    buildZoneGraph(N, M);
    colorNewGraph(czones);
    setEdges(N, M);
    writeAnswer(N, M);
}