Jimmy Blog

Welcome!

hihocoder:1138 Islands Travel

1138 : Islands Travel

本题链接:http://hihocoder.com/problemset/problem/1138

若两个点的x或y相等,则他们的距离为0。若a与b距离为0,b与c距离为0,则a与c距离也为0。可以将距离为0的点划分进同一个集合中。 这样就把所给的点划分成了多个集合,用最短路径算法计算开始与结束的点所在的集合的最短路径即可。 集合间的距离是两个集合中距离最小的两点的距离。获取集合间的距离是一个难点,将区域中的点映射到x轴和y轴上,仅仅需要遍历x轴和y轴中,相邻两个映射的点的距离,进行比较之后即可快速得到集合间的距离。 选取最短路径算法也是一个问题,Dijikstra算法复杂度是O(V*V+E),Bellman-Ford算法复杂度是O(VE),SPFA算法复杂度是O(kE)(k<<V)。分析可知,集合数量较多,即V较多,而集合间间的边较少,即E较少,所以采用SPFA算法。其他两个算法我也试过,都TLE,只有SPFA算法AC了。

能力有限,只能想到这样的。请大神指点。

#include <iostream>
#include <map>
#include <vector>
#include <list>
#include <cmath>
#include <queue>

using namespace std;

const int MAX = 1000000000;

typedef pair<int, int> pi;
typedef map<int, int>::iterator mpit;
typedef map<pi, int>::iterator mpiit;

void swap(int &a, int &b)
{
    a ^= b;
    b ^= a;
    a ^= b;
}

class Border{
public:
    int src, dest, len;
    Border(int src = 0, int dest = 0, int len = 0) : src(src), dest(dest), len(len){};
};

class Vertex{
public:
    int id, dis;
    int x, y;
    list<Border*> border;
    Vertex(int id) :id(id){ dis = MAX; };

    void AddBorder(int dest, int len)
    {
        border.push_back(new Border(id, dest, len));
    }
};


void GraphAddBorder(vector<Vertex*> &vertex, int u, int v, int len)
{
    if (vertex[u] == NULL)
        vertex[u] = new Vertex(u);

    if (vertex[v] == NULL)
        vertex[v] = new Vertex(v);

    vertex[u]->AddBorder(v, len);
    vertex[v]->AddBorder(u, len);
}

int Min(int a, int b)
{
    return a < b ? a : b;
}

void SPFAAddVertex(vector<Vertex*> &vertex, int id, queue<Vertex*> &waitQueue, vector<bool> &isInQueue)
{
    for (list<Border*>::iterator iter = vertex[id]->border.begin();
        iter != vertex[id]->border.end(); iter++)
    {
        int dest = (*iter)->dest, src = (*iter)->src, len = (*iter)->len;

        if (vertex[dest]->dis > vertex[src]->dis + len)
        {
            vertex[dest]->dis = vertex[src]->dis + len;

            if (!isInQueue[dest])
            {
                waitQueue.push(vertex[dest]);
                isInQueue[dest] = true;
            }
        }
    }
}

void SPFA(vector<Vertex*> &vertex, int S)
{
    queue<Vertex*> waitQueue;
    vector<bool> isInQueue(vertex.size(), false);

    vertex[S]->dis = 0;
    SPFAAddVertex(vertex, S, waitQueue, isInQueue);

    while (!waitQueue.empty())
    {
        int id = waitQueue.front()->id;
        waitQueue.pop();
        isInQueue[id] = false;
        SPFAAddVertex(vertex, id, waitQueue, isInQueue);
    }
}


int GetP(vector<int> &p, int a)
{
    int x = a;
    while (p[x] != 0)
        x = p[x];

    if (a != x)
        p[a] = x;

    return x;
}

void Merge(vector<int> &p, int a, int b)
{
    int pa = GetP(p, a),
        pb = GetP(p, b);

    p[pb] = pa;
}

void GetMinDis(map<pi, int> &pdis, vector<int> &p, vector<int> pv, map<int, int> &px)
{
    for (mpit iter = px.begin(); iter != px.end(); iter++)
    {
        mpit jter = iter;
        jter++;
        if (jter == px.end())
            break;

        int pa = GetP(p, iter->second), pb = GetP(p, jter->second);

        if (pa == pb)
            continue;

        pa = pv[pa];
        pb = pv[pb];

        if (pa > pb)
            swap(pa, pb);

        int pred = pdis[pi(pa, pb)];

        if (pred == 0)
            pdis[pi(pa, pb)] = abs(iter->first - jter->first);
        else
            pdis[pi(pa, pb)] = Min(pred, abs(iter->first - jter->first));
    }

}

int main()
{
    //freopen("t.txt", "r", stdin);
    int N;

    while (cin >> N)
    {
        vector<int> p(N + 1, 0);
        map<int, int> px, py;

        for (int i = 1; i <= N; i++)
        {
            int x, y;
            cin >> x >> y;

            if (px[x] == 0)
                px[x] = i;
            else
                Merge(p, px[x], i);

            if (py[y] == 0)
                py[y] = i;
            else
                Merge(p, py[y], i);

        }

        vector<int> pv(N + 1, 0);
        vector<Vertex*> v;

        int pn = 0;
        for (int i = 1; i <= N; i++)
        {
            if (p[i] == 0)
            {
                pv[i] = pn;
                v.push_back(new Vertex(pn));
                pn++;
            }
        }

        map<pi, int> pdis;

        GetMinDis(pdis, p, pv, px);
        GetMinDis(pdis, p, pv, py);


        for (mpiit iter = pdis.begin(); iter != pdis.end(); iter++)
        {
            int a = iter->first.first, b = iter->first.second,
                len = iter->second;

            GraphAddBorder(v, a, b, len);
        }

        int dest = pv[GetP(p, N)];

        SPFA(v, 0);
        cout << v[dest]->dis << endl;
    }

    return 0;
}

comments powered by Disqus