HDU 4725 The Shortest Path in Nya Graph 解题报告

24 篇文章 0 订阅
11 篇文章 0 订阅

题目大意

给了若干个点,每个点分属于一个层,同层之间的点不能够直接到达,但是相邻层的可以到达,代价是c,现在在这个基础之上,给了若干条无向边,现在要求结点1到结点n的路径的最小代价。

此题的难点在于建图

现在我们将层这个概念变成实际意义上的结点,层这个虚拟概念正式成为两个结点,第r层,对应的结点编号是,n + u * 2 - 1 ,和, n + u * 2 。i 结点对应的层数是r,那么 令 i 到 n + u * 2 - 1 有一条有向边, 令 n + u * 2 到 i 也有一条有向边 。两条有向边的代价均为 0 。

为什么将代价设为0 ?
层是结点的基础属性,由结点映射到层,不需要任何代价。

接下来我们给相邻层数建边。

			add_ead( n + 2 * i - 1 , n + 2 * (i + 1) , c );
			add_ead( n + 2 * (i + 1) - 1 , n + 2 * i , c );
为什么,点和层间,进入的层点,成为了,层和层间,出发的点 ?
为了形成一个环。
这样,由点,到层,再到层,再到点,这条路径,
在原图中对应的路径,才能吻合,
也就是说,我们要保证重新建立的图和原来的图要相互吻合。

继续建图,建立结点和结点之间的无向图。
接着利用dijkstra。

AC code

#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<map>
#include<vector>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<ctime>
using namespace std; 
#define rep(i,aa,bb) for(register int i=aa;i<=bb;i++)
#define rrep(i,aa,bb) for(register int i=aa;i>=bb;i--)
#define mset(var,val)	 memset(var,val,sizeof(var))
#define LL long long 
#define eps 0.000001
#define inf 0x7f7f7f7f
#define llinf 1e18
#define exp 0.000001
#define pai 3.141592654
#define random(x)   rand()%(x)
#define lowbit(x)   x&(-x)
inline int read()
{
	int x=0,y=1;char a=getchar();while ( a>'9' || a<'0'){if ( a=='-')y=-1;a=getchar();}
	while ( a>='0' && a<='9' ){	x=(x<<3)+(x<<1)+a-'0'; a=getchar();}return x*y;
}
#define N 500005
struct Ead{
	int u,v,w,nx;  
}e[N];int hea[N],tot;bool islay[N];int n,m,c,dis[N];
void init(){
	mset(hea,0);
	mset(islay,0);
	mset(dis,0x7f);
	tot = 0; 
}
void add_ead(int u,int v,int w){
	++tot; 
	e[tot].u = u; e[tot].v = v; e[tot].w = w; e[tot].nx = hea[u]; hea[u] = tot;  
}
struct Node {
	int v,w; 
	Node() {}
	Node ( int a_ ,int b_ ) {	v = a_ ; w = b_ ; }
	bool operator < ( const Node& aaa ) const {
		return w > aaa.w; 
	}
};
void dijkstra( int st ){
	dis[ st ] = 0 ; 
	priority_queue< Node >q ; 
	while ( !q.empty() )	q.pop() ;
	Node xxx ; xxx.v = 1; xxx.w = 0; 
	q.push( xxx );
	while ( !q.empty() ){
		Node now = q.top(); q.pop();
		if ( dis[ now.v ] != now.w )	continue; 
		for (int i = hea[ now.v ] ; i ; i = e[i].nx ){
			if ( dis[ e[i].v ] > dis[ e[i].u ] + e[i].w ){
//				printf("%d %d %d\n", e[i].u, e[i].v ,e[i].w);
				dis[ e[i].v ] = dis[ e[i].u ] + e[i].w;
				xxx.v = e[i].v ; xxx.w = dis[ e[i].v ];
				q.push( xxx );
			}
		}
	}
}
int main()
{
//	freopen("1.txt","r",stdin);
//	srand((int)time(0));
//	std::ios::sync_with_stdio(false);
	int T = read();
	rep(aai,1,T){
		init();
		n = read(); m = read(); c = read();
		rep(i,1,n){
			int u; u = read();
			add_ead( i , n + u * 2 - 1 , 0 );
			add_ead( n + u * 2 , i , 0 );
			islay[ u ] = true; 
		}
		rep(i,1,n){
			if ( islay[i] && islay[ i + 1 ] ){
				add_ead( n + 2 * i - 1 , n + 2 * (i + 1) , c );
				add_ead( n + 2 * (i + 1) - 1 , n + 2 * i , c );
			}
		}
		rep(i,1,m){
			int u,v,w; 
			u = read(); v = read(); w = read();
			add_ead(u,v,w);
			add_ead(v,u,w);
		}
		dijkstra(1);	
		if ( dis[ n ] == inf || n == 0 )
			printf("Case #%d: -1\n",aai);
		else 
			printf("Case #%d: %d\n",aai,dis[n]);	
	} 
	return 0;
}

此题卡 SPFA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值