E.千万别点进来,点进来你就哭了(最短路优化算法)

千万别点进来,点进来你就哭了

Time limit 2000 ms
题目链接https://csustacm.fun/problem/1089
Description

PY利用寒假摸鱼时间去了一趟香港吃吃吃,下面就由我介绍一下我遇到的好吃的香港美食。

首先介绍第一家合益泰小食,这家主打肠粉,这家的肠粉特别的正宗,价格非常亲民,口感非常好

公和荳品厂,这家的豆腐花特别好吃,超级嫩,口感又香又滑。

添好运——这是一家港式点心店,我推荐吃这里的糯米鸡和凤爪,口感都非常好,这里的虾饺也很好吃。

不过叉烧包太甜了,甜到我受不了了。

最后推荐一个华星冰室,不能多写了,不然题面写不下了。这里我极力推荐这家店的奶茶,

奶和茶混合的刚刚好的样子,没有以前我喝的以前的奶茶的那种过分甜,一点茶的味道都没有。(喝过很多奶茶,一个个都甜的不得了)
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
下面开始PY的香港之行,PY有n个要去的小吃店,这n个小吃店被m条路径联通起来。

PY有1个传送石和n-1个传送石碎片。

PY可以用传送石标记一个小吃店作为根据地。

每当PY吃完一个地点的美食,必须回到根据地(传送石标记的小吃店)休息一段时间,才能去另外一个小吃店。

也就是说你从根据地走去另一个小吃店吃完之后,不需要再走回来,用传送石碎片即可回来。

现在PY想知道他该标记那个小吃店才能让她走最短的路程吃完这nn个小吃店?

请聪明的你思考上述问题,并告诉他所需走的路程总和 和 他该标记那个地点作为根据地。

ps.传送石只能标记一个小吃店。

Input

第一行输入T,表示有T组数据。

每组数据第一行输入两个整数n,m,表示n家小吃店,有m条路径(1<=n<=1000 , 1<=m<=10000)

接下来m行,每行33个整数u,v,w 表示第u家小吃店到第v家小吃店有一条长度为w米的路径。(0<=w<=4e5),数据保证u!=v。

Output

输出两个整数 PY需要最少走多远才能吃完这n个小吃店的距离 和 被传送石标记的小吃店的标号。

如果距离相同,输出标号最小的。保证至少存在一个解

Sample Input 1

2
3 2
1 2 1
2 3 2
3 2
1 2 1
2 3 2
Sample Output 1

3 2
3 2
Hint

最优解:

标记2号点位根据地。从点2走到点1距离为1,然后利用传送石碎片回到根据地,再从点2走到点3距离为2,然后利用传送石碎片回到根据地,总距离和为3。


题目很详细。。。简单来说就是要跑最短路,枚举每一个点为起点,跑一遍最短路,求出所有点到起点的最短路,然后更新ans就OK了>~ ~<
当然普通的最短路肯定会超时,所以就用到了堆优化。。。最好的话用dj算法,1s内过
在这里插入图片描述

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define inf 999999999
#define ll long long
#define mac 1100
using namespace std;
int n, m;
struct node {
	int to, cost;
};
struct node2 {
	int id, d;
	bool friend operator < (node2 n1, node2 n2) {
		return n1.d > n2.d;
	}
};
vector<node>g[mac];
ll vis[mac];
ll dis[mac];
void myinit();
ll dj(int s);
void mst();
int main() {
	int i, j, x, y, c, s, t;
	while (scanf("%d%d", &n, &m)!=EOF) {
		myinit();
		for(i = 1; i <= m; i++) {
			scanf("%d%d%d", &x, &y, &c);
			node n1, n2;
			n1.to = x;
			n1.cost = c;
			n2.to = y;
			n2.cost = c;
			g[x].push_back(n2);
			g[y].push_back(n1);
		}
		ll mark,mans=inf;
		for (int i=1; i<=n; i++) {
			mst();
			ll ok=dj(i);
			if (ok<mans) {
				mans=ok;
				mark=i;
			}
		}
		printf ("%lld %lld\n",mans,mark);
	}
	return 0;
}
void myinit() {
	memset(vis, 0, sizeof(vis));
	for(int i = 0; i <mac; i++) {
		g[i].clear();
	}
	for (int i=1; i<=n; i++) dis[i]=inf;
}
ll dj(int s) {
	priority_queue<node2> q;
	dis[s] = 0;
	node2 nn1;
	nn1.id = s;
	nn1.d = dis[s];
	q.push(nn1);
	while(!q.empty()) {
		node2 nn2 = q.top();
		q.pop();
		int now = nn2.id;
		if(vis[now])continue;
		else vis[now] = 1;
		for(int i = 0; i < g[now].size(); i++) {
			if(!vis[g[now][i].to] && g[now][i].cost + dis[now] < dis[g[now][i].to]) {
				dis[g[now][i].to] = g[now][i].cost + dis[now];
				node2 nn3;
				nn3.id = g[now][i].to;
				nn3.d = dis[g[now][i].to];
				q.push(nn3);
			}
		}
	}
	ll sans=0;
	for (int i=1; i<=n; i++) sans+=dis[i];
	return sans;
}
void mst() {
	for (int i=1; i<=n; i++) dis[i]=inf;
	memset(vis, 0, sizeof(vis));
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值