1、早上
先看了ysj学长的博客里面的dijkstra的链式前向星和优先队列的优化代码,发现有点看不懂,然后去csdn搞懂了优先队列的大概意思,然后去写了一个dijkstra的优化题目。(3h)
#include <stdio.h>
#include <cstring>//memset
#define INF 2147483647
#define N 10001
#define M 500010
int e[N][N],dis[N],head[N],cnt;//head 链式前向星中存边的头,cnt编号
bool book[N];
struct edge{
int to;//边的终点
int w;//权重
int nxt;//指向同一个头的边的下一条编号
}edges[M];
void add(int u,int v,int w){//创建链式前向星
edges[++cnt].to=v;
edges[cnt].w=w;
edges[cnt].nxt=head[u];
head[u]=cnt;
}
int main(){
int n,m,s;
scanf("%d%d%d",&n,&m,&s);
while(m--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
memset(dis,0x3f,sizeof(dis));//将s到其它点的距离都赋为最大值
dis[s]=0;//s到本身的距离为0
for(int i=1;i<=n-1;i++){
int min=INF,u;
for(int j=1;j<=n;j++){ //找dis中未确定的最小值
if(!book[j]&&dis[j]<min){
min=dis[j];
u=j;
}
}
book[u]=true;//将dis中未确定的最小值确定
for(int j=head[u];j;j=edges[j].nxt){//根据链式前向星找出所有边的u,v,w,然后更新dis
int v=edges[j].to;
if(!book[v]&&dis[v]>dis[u]+edges[j].w)
dis[v]=dis[u]+edges[j].w;
}
}
for(int i=1;i<=n;i++)
printf("%d ",dis[i]==0x3f3f3f3f?INF:dis[i]);
return 0;
}
2、下午
首先先将不需要优化的dijkstra题目给做了,然后通过看博客还有B站视频学习dijkstra堆优化的完整过程,搞懂了整个优先队列对dijkstra优化的原理,之后在读代码时不太了解c++的优先队列,于是又去看相关的博客学习,搞懂了优先队列的一些基本知识。然后通过这些知识最后将本周最后一个堆优化的dijkstra题目给做了。(3.5h)
(1)邮递员送信
#include <stdio.h>
#define inf 99999999
#define Min(a,b) a<b?a:b
int e1[1010][1010],e2[1010][1010],dis[1010];//e1正向地图,e2反向地图
int n,m,cnt=0;
void dijkstra(int map[1010][1010]){
int book[1010]={0};
for(int i=1;i<=n;i++)//初始化dis
dis[i]=map[1][i];
book[1]=1;
for(int t=1;t<=n-1;t++){
int min=inf,u;
for(int i=1;i<=n;i++){
if(!book[i]&&dis[i]<min){
min=dis[i];
u=i;
}
}
book[u]=1;
for(int i=1;i<=n;i++){
if(dis[i]>dis[u]+map[u][i])
dis[i]=dis[u]+map[u][i];
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) e1[i][j]=e2[i][j]=0;
else e1[i][j]=e2[i][j]=inf;
while(m--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e1[u][v]=Min(e1[u][v],w);//本题坑点,有可能输入两次相同的路,但权值不一样 ,所以直接存权值最小的
e2[v][u]=Min(e2[v][u],w);//因为是反的地图,所以要交换i,j
}
dijkstra(e1);//正向走一遍
for(int i=1;i<=n;i++)
cnt+=dis[i];
dijkstra(e2);//反向走一遍
for(int i=1;i<=n;i++)
cnt+=dis[i];
printf("%d",cnt);
return 0;
}
(2)P4779 【模板】单源最短路径(标准版)
#include <bits/stdc++.h>
using namespace std;
#define INF 99999999
#define N 100010
#define M 200010
int dis[N],head[N],cnt;//head 链式前向星中存边的头,cnt编号
bool book[N];
//pair<-dis[i],i> 把-dis[i]和i合并在一起first=-dis second=i ;priority_queue默认为大项堆即整个队列降序,而给first前添负号,可以正好反过来形成小项堆
priority_queue<pair<int, int> > q;
struct edge{
int to;//边的终点
int w;//权重
int nxt;//指向同一个头的边的下一条编号
}edges[M];
void add(int u,int v,int w){//创建链式前向星
edges[++cnt].to=v;
edges[cnt].w=w;
edges[cnt].nxt=head[u];
head[u]=cnt;
}
int main(){
int n,m,s;
scanf("%d%d%d",&n,&m,&s);
while(m--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
memset(dis,0x3f,sizeof(dis));//将s到其它点的距离都赋为最大值
dis[s]=0;//s到本身的距离为0
q.push(make_pair(0,s));//初始化队列 把dis[s]和s存进去
while(!q.empty()){
int u=q.top().second;//每次拿出最小dis值的下标
q.pop();//已拿出就出队
if(book[u]) continue; //防止已出队数据重复入队,用book标记
book[u]=true;//标记为已出队
for(int j=head[u];j;j=edges[j].nxt){//根据链式前向星找出所有边的u,v,w,然后更新dis
int v=edges[j].to;
if(!book[v]&&dis[v]>dis[u]+edges[j].w){
dis[v]=dis[u]+edges[j].w;
q.push(make_pair(-dis[v],v));//把更小的dis入队
}
}
}
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
3、晚上
首先在复习前几天学习的知识点,过了一遍写的博客和代码,把之前写的每道题都重新搞懂,然后进行答辩,最后把今天的题解还有学习报告写完。(2.5h)
今日总共学习时长9h。