CodeChef - CLIQUED Bear and Clique Distances(最短路)

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.
题目链接

题意:输入的第一行包含一个整数T,代表测试数据的组数。接下来是T组数据。
每组数据的第一行包含五个整数N、K、X、M和S,分别代表城市数、古城数、古城间的道路长度、新建道路的条数,以及Limak居住在的城市编号。接下来M行,每行包含三个整数ai、bi和ci,代表有一条连接编号为ai和bi的城市的长度为ci的新建道路。保证不存在由一个城市连向自己的道路,所有道路两两不同,且任意城市间两两可达。编号为1-K的城市都是古城,那里的市民们喜欢秩序与规律。这些城市两两由长度为X的双向道路连接,共有K(K - 1) / 2条这样的道路。最后输出从s到其他各个城市的最短距离。

这个题目需要压缩点,压缩完之后就可以直接Dijkstra做了。因为1~k是古城,两两之间都是距离为x,但是这样数据量太大了,k(k-1)/2,所以我们可以抽象出一个虚拟的中间节点,我们规定,从第i个城市到0距离为0,从0到第i个城市距离为x。这样我们只需要最多建2×n条边就可以了。剩下的直接Dijkstra。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
ll head[maxn], book[maxn], dis[maxn];
ll cnt, n, k, x, m, st;

struct edge
{
	ll to, w, next;
}side[maxn << 1];

struct node
{
	ll pos, cost;
	node(){}
	bool operator < (const node &obj) const
	{
		return cost > obj.cost;
	}
	node(ll pos, ll cost):pos(pos), cost(cost){}
};

void init()
{
	memset(head, -1, sizeof(head));
	memset(book, 0, sizeof(book));
	memset(dis, 0x7f7f7f7f, sizeof(dis));
	cnt = 1;
}

void add(ll u, ll v, ll w)
{
	side[cnt].to = v;
	side[cnt].w = w;
	side[cnt].next = head[u];
	head[u] = cnt++;
}

void Dijkstra()
{
	dis[st] = 0;
	priority_queue<node> q;
	q.push(node(st, 0));
	while(q.size())
	{
		node now = q.top();	q.pop();
		if(book[now.pos])	continue ;
		book[now.pos] = 1;
		for(ll i = head[now.pos]; i != -1; i = side[i].next)
		{
			ll temp = side[i].to;
			if(book[temp])
				continue;
			if(dis[temp] > dis[now.pos]+side[i].w)
			{
				dis[temp] = dis[now.pos]+side[i].w;
				q.push(node(temp, dis[temp]));
			}
		}
	}
}

int main ()
{
	int T;
	cin >> T;
	while(T--)
	{
		init();
		scanf("%lld%lld%lld%lld%lld", &n, &k, &x, &m, &st);
		for(ll i = 1; i <= m; i++)
		{
			ll u, v, w;
			scanf("%lld%lld%lld", &u, &v, &w);
			add(u, v, w);
			add(v, u, w);
		}
		for(ll i = 1; i <= k; i++)
			add(i, 0, 0),   add(0, i, x);
		Dijkstra();
		for(ll i = 1; i < n; i++)
				printf("%lld ", dis[i]);
        printf("%lld\n", dis[n]);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值