HDU - 4725 The Shortest Path in Nya Graph 最短路,思维建图

题目链接

HDU-4725

题意

给定n个点m个带权双向道路,这n个点各自有一个叫层级的属性。相邻层级间的点可以通过花费c转移。求1-n最短路。

思路

这题可能是kuangbin这个专题里难度数一数二的了。思路很清晰,裸的最短路,难点在于建图。这个建图又和POJ - 2502里专门恶心人的建图不一样,是真的需要动脑子的。
关于层级,虽然层级范围是1-n,但没有告诉你一定是1-n全出现,也没有告诉你一个层级只有一个点。这意味着:

  • 离线处理变得困难
  • 只能连接相邻的两层,比如不加处理直接连接1-3层级,如果2层级不存在,那么这条路线是不可行的。

最容易想到的方法应该是两层for,但是n范围是1e5,肯定会t。这里我们选择为每一个层级建造一个层节点,有点类似于超级源点超级汇点。在线处理每一个节点,将这个节点所属的层节点向节点连单向边(如果双向,那么同一层级所有点相互移动的花费是0,显然会wa),之后再将这个节点向上下层级节点连接单向边。对于m条边正常连接,之后跑最短路即可
下附一张样例二图片,节点456代表层级123的层节点样例2

代码

#include<bits/stdc++.h>  
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
using namespace std;
	typedef long long ll;
	typedef pair <int,int> P;
	const int maxn=200500;
	const int maxe=800500;//开大点没坏处 ~ ~ 
	const int inf=0x3f3f3f3f;
	int head[maxn];
	struct Edge{
    
    
		int to;
		int next;
		int w;
	} edge[maxe];
	int cnt;
	int n,m,c;//点,边,跳跃花费 
 	int dis[maxn];
	void init(){
    
    
		cnt=0;
		memset(head,-1,sizeof(head));
		return ;
	}
	inline void add(int u,int v,int w){
    
    
		edge[cnt].next=head[u];
		edge[cnt].to=v;
		edge[cnt].w=w;
		head[u]=cnt;
		cnt++;
	}
			
	void dij(int start){
    
    
		memset(dis,0x3f,sizeof(dis));
		priority_queue<P,vector<P>,greater<P> > q;
		dis[start]=0;
		q.push(P(0,start));
		while(!q.empty()){
    
    
			P p=q.top(); q.pop();
			int v=p.second;
			
			if(dis[v]<p.first)		continue;
			
			for(int i=head[v];i!=-1;i=edge[i].next){
    
    
				int tmp=edge[i].to;
				if(dis[tmp]>dis[v]+edge[i].w){
    
    
					dis[tmp]=dis[v]+edge[i].w;
					q.push(P(dis[tmp],tmp));
				}
			}
		}
		return ;
	}
	int main(){
    
    
		IOS
		int tn;
		cin>>tn;
		for(int _=1;_<=tn;_++){
    
    
			init();
			cin>>n>>m>>c;
			for(int i=1;i<=n;i++){
    
    
				int l;
				cin>>l;
				add(l+n,i,0);//第l层层节点向i节点连单向边 
				if(l<n)
					add(i,l+n+1,c);//i节点向l+1层连单向边 
				if(l>1)
					add(i,l+n-1,c);//i节点向l-1层连单向边 
			}
			while(m--){
    
    
				int u,v,w;
				cin>>u>>v>>w;
				add(u,v,w);
				add(v,u,w);
			}
			dij(1);
			int ans=dis[n];
			if(ans==inf)
				ans=-1; 
			cout<<"Case #"<<_<<": "<<ans<<endl;
		}
		return 0;
	}

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/107746994
今日推荐