2.3学习总结

写单源最短路弱化版的时候,就已经快累死了,再来个标准版,一样的题,这数据妥妥天差地别QAQ。先把题复制过来:

题目背景

2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。

然后呢?

100→60100→60;

Ag→CuAg→Cu;

最终,他因此没能与理想的大学达成契约。

小 F 衷心祝愿大家不再重蹈覆辙。

题目描述

给定一个 �n 个点,�m 条有向边的带非负权图,请你计算从 �s 出发,到每个点的距离。

数据保证你能从 �s 出发到任意点。

输入格式

第一行为三个正整数 �,�,�n,m,s。 第二行起 �m 行,每行三个非负整数 ��,��,��ui​,vi​,wi​,表示从 ��ui​ 到 ��vi​ 有一条权值为 ��wi​ 的有向边。

输出格式

输出一行 �n 个空格分隔的非负整数,表示 �s 到每个点的距离。

输入输出样例

输入 #1复制

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出 #1复制

0 2 4 3

说明/提示

样例解释请参考 数据随机的模板题

1≤�≤1051≤n≤105;

1≤�≤2×1051≤m≤2×105;

�=1s=1;

1≤��,��≤�1≤ui​,vi​≤n;

0≤��≤1090≤wi​≤109,

0≤∑��≤1090≤∑wi​≤109。

本题数据可能会持续更新,但不会重测,望周知。

2018.09.04 数据更新 from @zzq

还好昨天学长讲了优先队列,不然一直TLE~__~!!!好吧,先上代码:

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int head[100001],cnt;
long long ans[1000000];//预防相加起来太大超过int
bool vis[1000000];
int m,n,s;
struct  Edge
{
	int to;
	int next;
	int w;
}edge[1000000];
struct priority
{
    int ans;
    int id;
    bool operator <(const priority &x)const//用取地址符不需要重新开辟空间
    {
        return x.ans<ans;
    }
};
void add(int x,int y,int z)
{
	edge[++cnt].to=y;
	edge[cnt].w=z;
	edge[cnt].next=head[x];
	head[x]=cnt;
}

priority_queue<priority> q;

int main()
{
	scanf("%d %d %d",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		ans[i]=2147483647;
	}
	ans[s]=0;
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		add(a,b,c);
	}
	int u;
	q.push((priority){0,s});//这里插入了第一个元素id=s,ans=0;
    while(!q.empty())
    {
        priority temp=q.top();
        q.pop();
        u=temp.id;
        if(!vis[u])
        {
        	vis[u]=1;
	        for(int i=head[u];i;i=edge[i].next)
	        {
	            int v=edge[i].to;
	            if(ans[v]>ans[u]+edge[i].w)
	            {
	                ans[v]=ans[u]+edge[i].w;
	                if(!vis[v])
	                {
	                    q.push((priority){ans[v],v});
	                }
	            }
	        }
		}
    }
	for(int i=1;i<=n;i++)
	{
		printf("%lld ",ans[i]);
	}
}

在解释代码前,来了解一下这个代码里面的有关新知识:

首先是#include<iostream>头文件,好像是每个c++必备用于这个cin和cout的输入输出,而且要带上这么一个东西:using namespace std; 而这个cstdio.h就是标准c++,用都也要加上using namespace std因为这里面的函数都是定义在一个名称空间std里面的;至于#include<queue>这个就是用优先队列的头文件。

对了说到这个,为什么这里还可以用printf和scanf,我百度了一下:

在C++下,若要使用C中已有库中的函数如stdio,文件包含方式为前面加一个c,同时去掉.h后缀

这里要注意,虽然printf和scanf的输入形式比cin和cout麻烦不少,但是他们速度快呀。 

struct priority
{
    int ans;
    int id;
    bool operator <(const priority &x)const//用取地址符不需要重新开辟空间
    {
        return x.ans<ans;
    }
};

这里本来定义了一个结构体,但是后面又加了一个

priority_queue<priority> q;

声明了了一个优先队列,而类型就是我们刚刚定义的结构体类型,队列名叫q,而优先队列之所以神奇就在于它可以自动排序,其实它是从大到小排序的,不对,应该说是在声明优先队列的时候,<>里面就只一个变量的话,默认排序是从大到小的,其实他后面省略了两个变量,这个声明原来的样子本来是这样的,prioirity_queue<priority,vector<priority>,less<priority> >中间这个是容器,表示用一个什么东西装,这里一般都不做大修改,而后面那个就是规则,比如这里less的规则就是小于,也就是按从大到小的规则排序,也就是我所说的默认排序,而如果想改成从小到大的话,可以把less改成greater,当然,我说这样改是指一般类型,像我们这里的这个要改的话,不仅要改这个,还要将那个规则上的operator <改成operator >,当然还有一个更好的办法,就是直接改operator下面括号里的<改成>

这个变量里面由于也带有<>所以一定要小心,在最后一个变量会出现>>这时候一定要把它从中间用空格隔开不然就成平移符号了

 bool operator <(const priority &x)const//用取地址符不需要重新开辟空间
    {
        return x.ans<ans;
    }

而结构体里面的这个就相当于在定规则,为什么还要定规则呢,那是因为结构体里面有多个元素,到底是根据哪个元素排,要定义规则,所以我们来浅浅解读一下这坨意思,意思是:如果结构体priority里面的ans大,那就结构体priority小,也就是不优先,意思就是说,ans小的结构体越优先越在前面;

在优先队列中有这么几种:

以队列q为例:

q.pop()输出堆顶;

q.push()插入元素;

q.top()返回堆顶;

q.empty()表示队列是否空了,空了即返回1,否则为0;

感觉有点缺斤少两,具体思想就和弱化版差不多。

(13条消息) 2.1学习总结_穿花云烛展的博客-CSDN博客

但是还是再清楚一点显得我的好态度:

while(!q.empty())
    {
        priority temp=q.top();
        q.pop();
        u=temp.id;
        if(!vis[u])
        {
        	vis[u]=1;
	        for(int i=head[u];i;i=edge[i].next)
	        {
	            int v=edge[i].to;
	            if(ans[v]>ans[u]+edge[i].w)
	            {
	                ans[v]=ans[u]+edge[i].w;
	                if(!vis[v])
	                {
	                    q.push((priority){ans[v],v});
	                }
	            }
	        }
		}
    }

来浅浅解释一下这一段优先队列用的最多的代码吧!先是在队列不为空的情况下,让一个临时变量来存下堆顶,并且先将它输出,为什么是堆顶呢,因为其实你会发现它的起点元素就在堆顶,不管循环多少次,然后再让u=temp.id,后面大概找到一个小的就存一个。思想详见(13条消息) 2.1学习总结_穿花云烛展的博客-CSDN博客

然后还是一碗鸡汤:太深的流连便成了一种羁绊,绊住的不仅是双脚,还有未来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值