建立一个虚拟点后用dijkstra

https://vjudge.net/contest/382787#problem/A
参考博客link
dijkstra参考模板link

Bearland consists of N cities, numbered 1 through N. Cities are connected with bidirectional roads.

Cities 1 through K were built a long time ago, when citizens liked order and regularity. Each pair of those old cities is connected with a road of length X. Note that this description generates K*(K-1)/2 roads.

There are M newer roads, not necessarily of the same lengths. The i-th of them connects cities ai and bi and has length ci.

There is no road that connects a city to itself. All M+K*(K-1)/2 roads are distinct (ie. no two of them connects the same pair of cities). It's guaranteed that it's possible to get from every city to every other city, using one or more roads.

Limak, a bear, lives in the city S. In order to plan a trip to some other city, for every city he wants to know how quickly he can get there. Can you help him and find the distance from S to every city?

The distance between two cities is the minimum total length of a path (sequence of roads) between the two cities.

Input

The first line of the input contains an integer T denoting the number of test cases. The description of T test cases follows.

The first line of each test case contains five integers N, K, X, M and S, denoting the number of cities, the number of old cities, the length of a road between every two old cities, the number of newer roads, and the city where Limak lives, respectively.

Each of the following M lines contains three integers ai, bi and ci, denoting a road of length ci between cities ai and bi.

As guaranteed above: no two cities are connected with more than one road, no road connects a city to itself, and it's possible to get from every city to every other city.
Constraints

    1 ≤ T ≤ 3
    2 ≤ K ≤ N ≤ 105
    0 ≤ M ≤ 105
    1 ≤ S, ai, bi ≤ N
    1 ≤ X, ci ≤ 109

Output

For each test case, output a single line containing N integers. The i-th of them should denote the distance from the city S to the city i. The distance from S to S is simply 0.

Sample Input

3
5 4 100 2 3
1 5 50
5 3 160
5 4 100 2 3
1 5 50
5 3 140
8 3 15 7 5
3 4 10
4 5 20
5 6 10
6 1 7
3 7 1000
7 8 50
3 5 1000000000

Sample Output

100 100 0 100 150 
100 100 0 100 140 
17 32 30 20 0 10 1030 1080

Hint

Test case 1. There are N = 5 cities. The first K = 4 of them are all connected with each other with roads of length X = 100. There are M = 2 extra roads:

    Cities 1 and 5 are connected with a road of length 50.
    Cities 5 and 3 are connected with a road of length 160.

We are asked to compute distances to all cities from the city S = 3. Note that the distance from a city to itself is 0, and this is why the third number in the ouput is 0.

解题思路:

  1. 在前k个顶点构成的完全图中,从任意一个顶点到另一个顶点的最短距离一定是x(直接走相邻边,不经过其他中间点),故若将完全图中的所有边加入图中,会有很多无效的松弛(TLE);
  2. 从外部点a(不在这个完全图中的顶点)到完全图中的点b的最短距离={a到完全图中每个点的距离}min + x,只需找到 {a到完全图中每个点的距离}min ,并用该值对完全图中所有点松弛一次即可;
  3. 为了实现 2 中的功能,引入一个虚拟点0,使编号为1到k的点到0的边长为0,而0到编号为1到k的点的边长为x
  4. 当优先队列中第一次弹出完全图中顶点temp时,该temp所对应的dis[temp]一定是完全图中最小的(即第2条中的min),用dis[temp]对其邻接边进行松弛(不会对完全图中的顶点松弛,因为完全图中的边并没有加入图中),松弛完后虚拟点0进入队列,并且当前dis[0]=dis[temp],所以接下来从队列中弹出来的是虚拟点0,用该值dis[0]即dis[temp]对完全图中的顶点进行松弛(即第2条的后半部分)
#include<bits/stdc++.h>
#define ll long long 
#define MAXN 100010
#define INF 0X3f3f3f3f
const ll inf=1e18;
using namespace std;

struct edge{
	int to,nex;
	ll val;
}e[500010];//从e[1]开始存边 
int head[MAXN];
int cnt;
void addedge(int from,int to,ll value){
	e[++cnt].to=to;
	e[cnt].val=value;
	e[cnt].nex=head[from];
	head[from]=cnt;
}

ll dis[MAXN];
bool vis[MAXN];
priority_queue<pair<ll,int> >q;//第一位是dis值,第二位是点的编号,自动按照first来建立大根堆 
void dijkstra(int s){
	dis[s]=0;
	q.push(make_pair(0ll,s));
	while(!q.empty()){
		int temp=q.top().second; q.pop();
		if(vis[temp])continue;
		vis[temp]=true;
		for(int i=head[temp];i;i=e[i].nex){
			int v=e[i].to;
			if(vis[v])continue;//可以去掉 
			if(dis[temp]+e[i].val<dis[v]) dis[v]=dis[temp]+e[i].val;
			q.push(make_pair(-dis[v],v));存入dis值的相反数,把大根堆变为小根堆;
		} 
	}
	
}

void init(int n){
	for(int i=0;i<=n;i++){
		head[i]=0;
		dis[i]=inf;
		vis[i]=false;
	}
	cnt=0;
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,k,m,s;
		ll x;
		scanf("%d%d%lld%d%d",&n,&k,&x,&m,&s);
		init(n);
		int a,b;
		ll c;
		for(int i=1;i<=m;i++){
			scanf("%d%d%lld",&a,&b,&c);
			addedge(a,b,c);
			addedge(b,a,c);
		}
		for(int i=1;i<=k;i++){
			addedge(i,0,0);
			addedge(0,i,x);
		}
		dijkstra(s);
		for(int i=1;i<=n;i++){
			printf("%lld ",dis[i]);
		}
		printf("\n");
	}
}

你可能感兴趣的:(ACM暑期集训)