农场派对 C++


题目描述

N(1≤N≤1000)头牛要去参加在某农场举行的一场编号为x(1≤x≤N)的牛的派对。有M(1≤M≤100000)条有向道路,每条道路长Ti(1≤Ti≤100);每头牛参加派对后都必须回到家,每头牛都会选择最短路。求这N头牛的最短路(一个来回)中最长的一条的长度。

特别提醒:可能有权值不同的重边。


输入输出格式

输入格式:

第一行,3个空格分开的整数N,M,X。
第二行至第M+1行:3个用空格分开的整数Ai,Bi,Ti,表示有一条从Ai到Bi的路长度为Ti。

输出格式:

一行:最长的最短路长度。



输入输出样例

输入样例:

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

输出样例:

10


分析

一道最短路径的题目
我的方法是用 spfa 算法,再进行一些简单优化


spfa算法

算法分析

1.用dis数组记录点到有向图的任意一点距离,初始化起点距离为0,其余点均为INF,起点入队。
2.判断该点是否存在。(未存在就入队,标记)
3.队首出队,并将该点标记为没有访问过,方便下次入队。
4.遍历以对首为起点的有向边(t,i),如果dis[i]>dis[t]+w(t,i),则更新dis[i]。
5.如果i不在队列中,则入队标记,一直到循环为空。

例题

P3371 【模板】单源最短路径(弱化版) - 洛谷

想练习 spfa 算法的可以去 洛谷 上练练手

详细请看 spfa


我还用了一种容器----deque(双端队列)

双端队列deque

简介

deque,即双端队列(double ended queue),是一种可以在两端扩展或收缩的序列化容器。
deque 是C++ 标准模板库的一部分,想要使用 deque,需要在程序中包含头文件 deque 。

#include<deque>
迭代器

deque.begin():指向deque首个元素。
deque.end():指向deque尾元素的下一个位置。
deque.rbegin():指向deque尾元素的反向迭代器,即rbegin()指向尾元素,rbegin-1指向倒数第二个元素。
deque.rend():指向deque头元素前一个位置的反向迭代器,即rend()指向头元素前一个位置元素,rbegin-1指向第一个元素
deque.cbegin():指向deque首元素,与begin()相同。增加了const属性,不能用于修改元素。
deque.cend():指向deque尾元素下一个位置,与end()相同。增加了const属性,不能用于修改元素。
deque.crbegin():指向deque尾元素的反向迭代器,与rbegin()相同。增加了const属性,不能用于修改元素。
deque.crend():指向deque头元素前一个位置的反向迭代器,与rend()相同。增加了const属性,不能用于修改元素。

用法(函数)
  1. size()——元素个数
  2. max_size()——最多能容纳元素个数
  3. resize(n)——改变deque大小为n
  4. empty()——判断deque是否为空
  5. shrink_to_fit()——要求deque减小容量已适应元素个数
  6. at()——访问deque元素
  7. front()和back()——访问deque头尾元素
  8. assign()——指定deque元素
  9. push_back()——添加元素(deque尾部)
  10. push_front()——添加元素(deque头部)
  11. pop_back()——移除deque元素(尾部)
  12. pop_front()——删除deque元素(头部)
  13. insert()——添加元素(任意位置)
  14. erase()——删除元素(任意位置)
  15. clear()——清空元素
  16. swap()——交换元素
  17. emplace()——插入元素
  18. emplace_back()——在deque尾部插入元素
  19. emplace_front()——在deque尾部插入元素

***详细请看这里 双端队列deque ***


废话不多说,我们来看一看代码



Code

注意 :int 不能改为 long long 已经试过会出错,以为0x3f3f3f3f是 int 的最大值, long long 的最大值是 0x7fffffff ,但是用 0x7fffffff 会报错(我也不知道为什么),知道原因的请在评论区支指出,谢谢~

本代码AC速度 14 毫秒 ,速度超快

#include<iostream>
#include<cstdio>
#include<deque>
#include<cstring>
using namespace std;
int n,m,x,a,b,t,i,j,f[1100][1100],d[1100],vis[1100],dd[1100],sum=0,ans=0;
int main()
{
	memset(vis,0,sizeof(vis));
	memset(d,0x3f3f3f3f,sizeof(d));
	scanf("%d%d%d",&n,&m,&x);
	for(i=1;i<=1000;i++)
		for(j=1;j<=1000;j++)
			f[i][j]=0x3f3f3f3f;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&t);
		f[a][b]=min(f[a][b],t);
	}
	d[x]=0;
	deque<int>q;
	q.push_front(x);
	while(!q.empty())
	{
		t=q.front();
		q.pop_front();
		if((q.size()+1)*d[t]>sum)
		{
			q.push_back(t);
			continue;
		}
		sum-=d[t];
		vis[t]=0;
		for(i=1;i<=n;i++)
		{
			if(f[t][i]!=0x3f3f3f3f&&d[i]>d[t]+f[t][i])
			{
				d[i]=d[t]+f[t][i];
				if(!vis[i])
				{
					vis[i]=1;
					sum+=d[i];
					if(q.empty()||d[i]>d[q.front()])
						q.push_back(i);
					else
						q.push_front(i);
				}
			}
		}
	}
	q.clear();
	memset(dd,0x3f3f3f3f,sizeof(dd));
	memset(vis,0,sizeof(vis));
	dd[x]=0;
	q.push_front(x);
	sum=0;
	while(!q.empty())
	{
		t=q.front();
		q.pop_front();
		if(q.size()*d[t]>sum)
			q.push_back(t);
		sum-=dd[t];
		vis[t]=0;
		for(i=1;i<=n;i++)
		{
			if(f[i][t]!=0x3f3f3f3f&&dd[i]>dd[t]+f[i][t])
			{
				dd[i]=dd[t]+f[i][t];
				if(!vis[i])
				{
					vis[i]=1;
					sum+=dd[i];
					if(q.empty()||dd[i]>d[q.front()])
						q.push_back(i);
					else
						q.push_front(i);
				}
			}
		}
	}
	for(i=1;i<=n;i++)
		if(d[i]!=0x3f3f3f3f&&dd[i]!=0x3f3f3f3f)
			ans=max(ans,d[i]+dd[i]);
	printf("%d",ans);
	return 0;
}
//spfa

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值