【Luogu P1342】请柬

请 柬 请柬

L u o g u P 1342 Luogu P1342 LuoguP1342

题目背景

在电视时代,没有多少人观看戏剧表演。 Malidinesia 古董喜剧演员意识到这一事实,他们想宣传剧院,尤其是古色古香的喜剧片。

题目描述

他们已经打印了请帖和所有必要的信息和计划。许多学生被雇来分发这些请柬。每个学生志愿者被指定一个确切的公共汽车站,他或她将留在那里一整天,邀请人们参与。

这里的公交系统是非常特殊的:共有 n 个站点和 m 个线路,所有的线路都是单向的,连接两个站点。公共汽车离开起始点,到达目的地之后又空车返回起始点。

学生每天早上从总部所在的 1 号站点出发,乘公交车到一个预定的站点邀请乘客。每个站点都被安排了一名学生。在一天结束的时候,所有的学生都回到总部。现在需要知道的是,学生所需的公交费用的总和最小是多少。

输入格式

输入的第一行是两个整数,代表站点个数 n 和线路条数 m

第 2 到第 (m + 1) 行,每行三个整数 u, v, w代表存在一条从 u 出发到达 v 的线路,费用为 w

输出格式

输出一行一个整数,表示最小费用。

输入输出样例

输入样例

4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50

输出样例

210 

说明/提示

数据规模与约定
对于 100% 的数据,保证:
1≤n,m≤10^6
1≤u,v≤n
1≤w≤10^9

从 1 出发可以到达所有的站点

解题思路

代码如下

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,m,p,u,v,w,ans,t[1000001],tt[1000001],k,d[1000001],dd[1000001];

struct node
{
long long to,next,x;//to表示这个儿子是谁(GJY)   next表示下一个儿子的位置  x表示父亲到当前儿子的边的距离(值) 
}e1[2000001],e2[2000001];
queue<long long>q;
bool in[1000001];//判断是否走过
int main()
{
	memset(d, 0x7f, sizeof(d));
	memset(dd, 0x7f, sizeof(dd));
	scanf("%lld%lld",&n,&m);
	p = 1;//初始值
	for(long long i = 1;i <= m;++i)
	{
		scanf("%lld%lld%lld",&u,&v,&w);
		e1[++k] = (node){v, t[u], w}; //把边的值赋
		t[u] = k;
		e2[k] = (node){u, tt[v], w}; //同上
		tt[v] = k;
	}
	q.push(p);//起点插入队列 
	in[p] = 1;//记录到过这个点 
	d[p] = 0;//距离 
	while(!q.empty())//还有下一个点可以走 
	{
		long long now = q.front();//现在在那个点 
			q.pop();//把这个点弹出去 
		for (long long  i = t[now]; i; i = e1[i].next)//枚举它所有到的点 
		{
			long long y = e1[i].to;//到它的下一个点 
			if (d[now] + e1[i].x < d[y])//判断哪个距离短 
			{
				d[y] = d[now] + e1[i].x;//如果更短,就更新值 
				if (!in[y])//如果没有到过这个点(避免死循环) 
				{
					in[y] = 1;//标记它走过 
					q.push(y);//插入点继续走 
				}
			}
		}
		in[now] = 0;//把不在路径上的点的标记清除 
	}
	
	q.push(p);//下面是反过来的SPFA
	in[p] = 1;
	dd[p] = 0;
	while(!q.empty()) 
	{
		long long now = q.front();
		q.pop();
		for (long long i = tt[now]; i; i = e2[i].next) 
		{
			long long y = e2[i].to;
			if (dd[now] + e2[i].x < dd[y]) 
			{
				dd[y] = dd[now] + e2[i].x;
				if (!in[y]) 
				{
					in[y] = 1;
					q.push(y);
				}
			}
		}
		in[now] = 0;
	}
	
	for(long long i = 1;i <= n; ++i)//因为两边SPFA求出来的都是最优的,所以相加即可
		if(i != p) ans += d[i] + dd[i];
	printf("%lld",ans);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值