【HZOI】 Path

Description

Loongint非常喜欢Dota这款游戏~但是他总是被Dota复杂的地图困扰,有时候甚至会因为地图太复杂而失去了自己Gank和Farm的节奏。所以他需要你的帮忙。 

地图上一共有n个关键位置,每个关键位置有一个关键值Vi, 关键位置之间有m条双向的通路,每条通路有其通行值Ci,我们定义两关键位置之间的距离为其间的通路的通行值和加上路径上关键值最大的关键位置(包括起点终点)的关键值(样例如图)。 

Loongint现在有Q个询问,对于每个询问,你需要告诉他a关键位置和b关键位置间的最短距离。 



Input

第1行为三个数 n,m,q, 
第2行到第n+1行表示关键位置的关键值Vi, 
第n+2到第n+m+1行表示通路的起始位置和通行值, 
第n+m+2到第n+m+q+1行表示q个询问,每个询问给出a,b。

Output

输出q行,每行对应一个询问的最短距离。

Sample Input

5 7 2 
2 
5 
3 
3 
4 
1 2 3 
1 3 2 
2 5 3 
5 3 1 
5 4 1 
2 4 3 
3 4 4 
1 4 
2 3 

Sample Output

8 
9

Hint

N≤250,M≤10,000 

Q≤10,000;Vi,Ci≤100,000 


【分析】

        首先看到N只有250,显然O(N^3)的算法是可行的。于是便想到了floyd,又联想到floyd是基于DP原则,那么这道题应该就是这个方向了。由floyd算法知,最外层循环若走到k这个值,那么邻接矩阵中的数的意义就是以{1,2,...,k}为中介的最短路。于是,我们把顶点按权值从小到大排序,以此对顶点重编号。然后按照这个编号的顺序,在最外层循环。可知第 k(u,v <= k) 次外层迭代后,d[u][v] + w[k] 就是以 k 为最大权值顶点的最小花费。


【代码】

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<iostream>
#include<algorithm> 
using namespace std;
int N,M,Q;
int v[255],t[255],Map[255][255],g[255][255],rank[255];
void _in(int &x)
{
	char t=getchar();
	while(t<'0'||'9'<t) t=getchar();
	for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());
}
void _out(int x,int j=1)
{
	char t[100];
	if(!x) putchar('0');
	for(;x;x/=10,j++) t[j]=x%10+'0';
	for(j--;j;j--) putchar(t[j]);
	putchar('\n');
}
void _init()
{
	int x,y,z;
	_in(N);_in(M);_in(Q);
	for(int i=1;i<=N;i++)
	{
	    for(int j=1;j<=N;j++)
	        Map[i][j]=g[i][j]=999999999;
	    Map[i][i]=g[i][i]=0;
	    rank[i]=i;
	}
	for(int i=1;i<=N;i++)
	    _in(v[i]);
	for(int i=1;i<=M;i++)
	{
		_in(x);_in(y);_in(z);
		if(Map[x][y]>z)
		{
			Map[x][y]=z;
			Map[y][x]=z;
		}
	}
}
void _qst_t(int l,int r)
{
	int i=l,j=r,mt=t[(i+j)>>1];
	while(i<=j)
	{
		while(t[i]<mt) i++;
		while(t[j]>mt) j--;
		if(i<=j)
		{
			swap(t[i],t[j]);
			swap(rank[i],rank[j]);
			i++;j--;
		}
	}
	if(l<j) _qst_t(l,j);
	if(i<r) _qst_t(i,r);
}
void _solve()
{
	memcpy(t,v,sizeof(v));
	_qst_t(1,N);
	for(int o=1;o<=N;o++)
	{
		int k=rank[o];
	    for(int i=1;i<=N;i++)
	        for(int j=1;j<=N;j++)
	            if(Map[i][j]>=Map[i][k]+Map[k][j])
	            {
	                Map[i][j]=Map[i][k]+Map[k][j];
	                g[i][j]=min(g[i][j],Map[i][j]+max(v[k],max(v[i],v[j])));
	            }
	}
	int x,y;
	for(int i=1;i<=Q;i++)
	{
		_in(x);_in(y);
		_out(g[x][y]);
	}
}
int main()
{
	_init();
	_solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值