jzoj3086,luogu3831-[SHOI2012]回家的路【最短路,拆点】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/86611809

正题

luogu评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P3831


题目大意

n n n*n 的铁路网走一格代价为2, m m 个中转站可以改变方向代价为1。求两个点之间的最短路。


解题思路

我们发现 n n n*n 很大,所以我们考虑根据 m m 建图。算上起点和终点为中转站。

对于每个中转站,我们只连接上下左右最近的点,这个排序可以做到。这样边数就不会太多。可是如何解决转向的问题。

对于每个点,拆成横点和纵点,横着的连横点,竖着的连纵点,横点和纵点之间建立一条边,长度为1。

问题完美解决


c o d e code

#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#define py(aaa) aaa*2-1
#define px(aaa) aaa*2
using namespace std;
const int N=200100,L=20010;
struct node{
	int to,next,w;
}a[N*5];
vector<int> in_x[L],in_y[L];
queue<int> q;
int ls[N],tot,n,m,f[N],v[N],x[N],y[N];
bool cmp_x(int xs,int ys)
{return y[xs]<y[ys];}
bool cmp_y(int xs,int ys)
{return x[xs]<x[ys];}
void addl(int x,int y,int w)
{
	a[++tot].to=y;a[tot].w=w;
	a[tot].next=ls[x];ls[x]=tot;
}
int spfa(int s,int t)
{
	memset(f,0x3f,sizeof(f));
	f[py(s)]=f[px(s)]=0;
	q.push(py(s));q.push(px(s));
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=ls[x];i;i=a[i].next)
		{
			int y=a[i].to;
			if(f[x]+a[i].w<f[y]){
				f[y]=f[x]+a[i].w;
				if(!v[y]){
					q.push(y);
					v[y]=true;
				}
			}
		}
		v[x]=false;
	}
	if(f[px(t)]>=1061109567) return -1;
	return min(f[px(t)],f[py(t)]);
}
int main()
{
	scanf("%d%d",&n,&m);
	m+=2;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x[i],&y[i]);
		in_x[x[i]].push_back(i);in_y[y[i]].push_back(i);
		addl(px(i),py(i),1);addl(py(i),px(i),1);
	}
	for(int i=1;i<=n;i++)
	  sort(in_x[i].begin(),in_x[i].end(),cmp_x);
	for(int k=1;k<=n;k++)
	  for(int i=0;i+1<in_x[k].size();i++)
	  {
		  int as=in_x[k][i],bs=in_x[k][i+1];
		  addl(px(as),px(bs),(y[bs]-y[as])*2);
		  addl(px(bs),px(as),(y[bs]-y[as])*2);
	  }
	for(int i=1;i<=n;i++)
	  sort(in_y[i].begin(),in_y[i].end(),cmp_y);
	for(int k=1;k<=n;k++)
	  for(int i=0;i+1<in_y[k].size();i++)
	  {
		  int as=in_y[k][i],bs=in_y[k][i+1];
		  addl(py(as),py(bs),(x[bs]-x[as])*2);
		  addl(py(bs),py(as),(x[bs]-x[as])*2);
	  }
	printf("%d",spfa(m-1,m));
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/86611809
今日推荐