[SHOI2012]回家的路

题目链接:[SHOI2012]回家的路


每次到换乘点有两种决策。换乘或者是不换。显然可以dp或者分层图。

分层图比较好写。

我们直接按照横的路建边作为第一层,竖的路建边作为第二层。换乘点可以花费1横竖相通。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10,M=2e6+10;
int n,m,cnt,base,vis[N],d[N];
int head[N],nex[M],to[M],w[M],tot;
struct node{int x,y,id;}t[N];
int cmpx(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
int cmpy(node a,node b){return a.y==b.y?a.x<b.x:a.y<b.y;}
inline void ade(int a,int b,int c){
	to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c){ade(a,b,c);	ade(b,a,c);}
int Dijkstra(int s,int t){
	priority_queue<pair<int,int> > q; memset(d,0x3f,sizeof d); 
	d[s]=0;	q.push({0,s});
	while(q.size()){
		int u=q.top().second;	q.pop();
		if(u==t)	return d[t];
		if(vis[u])	continue;	vis[u]=1;
		for(int i=head[u];i;i=nex[i]){
			if(d[to[i]]>d[u]+w[i]){
				d[to[i]]=d[u]+w[i];	q.push({-d[to[i]],to[i]});
			}
		}
	}
	return d[t];
}
signed main(){
	cin>>n>>m;	base=m+2;
	for(int i=1;i<=m+2;i++){
		scanf("%d %d",&t[i].x,&t[i].y);	t[i].id=i;
		if(i<=m)	add(i,i+base,1);
	}
	sort(t+1,t+3+m,cmpx);
	for(int i=2;i<=m+2;i++)	if(t[i].x==t[i-1].x)	
		add(t[i-1].id+base,t[i].id+base,2*abs(t[i-1].y-t[i].y));
	sort(t+1,t+3+m,cmpy);
	for(int i=2;i<=m+2;i++)	if(t[i].y==t[i-1].y)	
		add(t[i-1].id,t[i].id,2*abs(t[i-1].x-t[i].x));
	add(m+1,m+1+base,0),add(base,base*2,0);
	int res=Dijkstra(m+1,m+2);
	if(res==0x3f3f3f3f)	res=-1;
	cout<<res;
	return 0;
}
发布了604 篇原创文章 · 获赞 242 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104354167