solution-p3831
题解 P3831 【[SHOI2012]回家的路】
这是我们学校膜你赛上的一道题。
感觉并没有紫题难度?
思路
一眼最短路,发现\(m \le 100000\),如果枚举每两个点的话会爆掉。
那么换一种建边方式罢。
显然两个点可以互相到达,当且仅当它们的x坐标相同或y坐标相同
于是我们用一个vector记录相同x上的点,枚举每两个点,连一条边。
当然也用一个vector记录相同y上的点,枚举每两个点,连一条边。
这里我们在连边的时候把换乘要用的1min也给算到边权里,当然到终点是不用换乘的,所以最终答案要减1。
最后对起点跑一遍dijkstra,直接输出即可。
代码
// 此处应有头文件
#define pr_q priority_queue
const int N = 2e6 + 10;
const int inf = 0x3fffffff;
int n,m,cnt,s = 0;
int head[N];
int dis[N];
bool vis[N];
struct edge
{
int v,w,nxt;
}edge[N];
struct node
{
int x,y;
}a[N];
void add(int u , int v , int w) // 前向星
{
++cnt;
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].nxt = head[u];
head[u] = cnt;
return ;
}
int sx,sy,fx,fy;
vector<int> samex[N],samey[N]; // samex[i]存下了所有x坐标为i的点。samey同理
struct prq // 用于dijkstra的优先队列。
{
int num,dis;
bool operator < (const prq &x) const
{return x.dis < dis;}
};
void dijkstra() // 朴素dijkstra
{
for(int i = 1;i <= m;i++)
dis[i] = inf;
dis[s] = 0;
pr_q<prq> q;
q.push( (prq){s , 0} );
while( !q.empty() )
{
int u = q.top().num;
q.pop();
for(int i = head[u];i;i = edge[i].nxt)
{
int v = edge[i].v;
if(dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if( !vis[v] )
{
vis[v] = true;
q.push( (prq){ v , dis[v] } );
}
}
}
}
}
int main()
{
cin >> n >> m;
for(int i = 1;i <= m;i++)
{
cin >> a[i].x >> a[i].y;
samex[a[i].x].push_back(i);
samey[a[i].y].push_back(i);
}
cin >> sx >> sy >> fx >> fy;
a[0] = (node){sx , sy}; // 起点
samex[sx].push_back(0);
samey[sy].push_back(0);
a[++m] = (node){fx , fy}; // 终点
samex[fx].push_back(m);
samey[fy].push_back(m);
// 建边
for(int x = 1;x <= n;x++)
for(int i = 0;i < samex[x].size();i++)
for(int j = i + 1;j < samex[x].size();j++)
{
int u = samex[x][i];
int v = samex[x][j];
add(u , v , abs(a[u].y - a[v].y) * 2 + 1); // 同时把换乘的时间算上
add(v , u , abs(a[u].y - a[v].y) * 2 + 1);
}
for(int y = 1;y <= n;y++)
for(int i = 0;i < samey[y].size();i++)
for(int j = i + 1;j < samey[y].size();j++)
{
int u = samey[y][i];
int v = samey[y][j];
add(u , v , abs(a[u].x - a[v].x) * 2 + 1);
add(v , u , abs(a[u].x - a[v].x) * 2 + 1);
}
dijkstra();
if(dis[m] == inf) // 无法到达
puts("-1");
else
cout << dis[m] - 1 << endl; // 最后减1,终点不需要花时间换乘
return 0;
}

浙公网安备 33010602011771号