Welcome!
本题链接: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;
}