题意,求1到n的最短路。不难想到单源最短路,难点在于数量级太大,因此如何建图是关键; 因为cost = min{|Xi-Xj|, |Yi-Yj|};所以,点i的移动只有两种情况,1. x距离最近的点,2. y距离最近的点 如此一来,每个点i的最多只有四条边(为什么是四条?),这样复杂度就降下来了,单源最短路的复杂度为n*m(点*边数) 我用spfa。 解题思路: x轴排序,建图 y轴排序,建图 求最短路 用spfa注意队列que的大小至少是n*m,可以使用循环队列 #include <cstdio> #include <cstring> #include <vector> #include <string> #include <iostream> #include <algorithm> using namespace std; const int N = 100010; struct node { int v; int i; bool operator < (const node &t)const { return v < t.v; } }x[N],y[N]; vector<int>g[N]; int p[N][2]; int ABS(int x) { return x >= 0 ? x : -x; } long long get_value(int i,int j) { return min(ABS(p[i][0]-p[j][0]),ABS(p[i][1]-p[j][1])); } bool flag[N]; long long dist[N]; int que[N]; long long spfa(int s,int n) { memset(flag,false,sizeof(flag)); memset(dist,0x7f,sizeof(dist)); int head = 0,tail = 0; dist[s] = 0; flag[s] = true; que[tail++] = s; while(head != tail) { int tep = que[head++]; if(head >= N) head = 0;//循环队列 flag[tep] = false; for(int i = 0; i < g[tep].size(); i++) { int v = g[tep][i]; if(dist[v] > dist[tep] + get_value(v,tep)) { dist[v] = dist[tep] + get_value(v,tep); if(!flag[v]) { que[tail++] = v; if(tail >= N) tail = 0;//循环队列 flag[v] = true; } } } } return dist[n-1]; } int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i = 0; i < N; i++) g[i].clear(); for(int i = 0; i < n; i++) { scanf("%d %d",&p[i][0],&p[i][1]); x[i].v = p[i][0]; x[i].i = i; y[i].v = p[i][1]; y[i].i = i; } sort(x,x+n); sort(y,y+n); for(int i = 1; i < n; i++) { int u = x[i-1].i; int v = x[i].i; //这里可以去下重 g[u].push_back(v); g[v].push_back(u); } for(int i = 1; i < n; i++) { int u = y[i-1].i; int v = y[i].i; //这里可以去下重 g[u].push_back(v); g[v].push_back(u); } printf("%lld\n",spfa(0,n)); } return 0; }
时间: 2024-10-07 02:49:35