acwing算法基础课学习记录2(2024.3.29)

对昨日的补充

朴素dijkstra算法
模板:
      1.dist[i]=+INF dist[1]=0
      2. for i 1~n     n次
            t<-不在s中的距离最近的点  (s:当前已经确定最短距离的点存储在内)  n次
            s<-t         n次
            用t更新其他点的距离   总共m次
堆优化版dijkstra
模板:
      1.dist[i]=+INF dist[1]=0
      2. for i 1~n     n次
            t<-不在s中的距离最近的点  (s:当前已经确定最短距离的点存储在内)  朴素:n次  堆:o(1)
            s<-t         n次
            用t更新其他点的距离   朴素:总共m次  堆:多了把更新的点push到堆 总共 用优先队列mlogm次相当于mlogn  用手写堆nlogn

今日把直播课搜索与图论(2)看完了,并且完成了相关的练习题

bellman

bellman-ford算法
        bellman算法 边可以用任意东西来存边,有负权边回路可能无解,但如果负环不在路径上就不影响(spfa算法要求一定没有负环)
        迭代k次的dist数组的数代表从1号点走不超过k条边的最短距离  由此可知如果第n次循环有更新,肯定有一个最短路径是经过n条边,则这个最短路经过n+1个点,推断得知有负环
模板:     for n次
            备份
            for所有边abw
                dist[b]=min(dist[b],dist[a]+w);

题目:有边数限制的最短路

//没啥可说的 边看边写的,和抄的差不多
#include<iostream>
#include<cstring>
using namespace std;
const int  N=10010;
struct Edge{
    int a,b,c;
}edge[N];
int n,m,k;
int dist[510],backup[510];
int bell(){
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=0;i<k;i++){
        memcpy(backup,dist,sizeof dist);
        for(int j=0;j<m;j++){
            dist[edge[j].b]=min(dist[edge[j].b],backup[edge[j].a]+edge[j].c);
        }
    }
    return dist[n];
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        edge[i].a=x,edge[i].b=y,edge[i].c=z;
    }
    bell();
    if(dist[n]>0x3f3f3f3f/2)cout<<"impossible";
    else cout<<dist[n];

}

spfa算法

spfa算法
模板:
      queue<-1
      while queue不空
           t<-q.front q.pop
           用t遍历所有出边b
             if(b不在队列)  queue<-b

题目:

spfa求最短路

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=100010;
int h[N],e[N],ne[N],w[N],idx;
int n,m;
int dist[N];
int st[N];
void add(int a,int b,int c){
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void spfa(){
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    queue<int>q;
    q.push(1);
    st[1]=1;
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=0;

        for(int j=h[t];j!=-1;j=ne[j]){
            if(dist[e[j]]>dist[t]+w[j]){
                dist[e[j]]=dist[t]+w[j];
                if(st[e[j]])continue;
                q.push(e[j]);
                st[e[j]]=1;
            }
        }

    }
    return;
}
int main(){
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    spfa();
    if(dist[n]==0x3f3f3f3f)cout<<"impossible";
    else cout<<dist[n];

}

spfa判断负环

//误打误撞提交上对了,和模板区别挺大的,看不懂 以后再想想吧,先按照模板写
//模板就不贴了
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=100010;
int h[N],e[N],ne[N],w[N],idx;
int n,m;
int dist[N];
int st[N];
void add(int a,int b,int c){
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int cnt[N];
int spfa(){
    // memset(dist,0x3f,sizeof dist);
    memset(st,1,sizeof st);
    dist[1]=0;
    queue<int>q;
    // q.push(1);
    st[1]=1;
    for(int i=1;i<=n;i++)q.push(i);
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=0;

        for(int j=h[t];j!=-1;j=ne[j]){
            if(dist[e[j]]>dist[t]+w[j]){
                dist[e[j]]=dist[t]+w[j];
                if(st[e[j]])continue;
                q.push(e[j]);
                st[e[j]]=1;
                cnt[e[j]]++;
                if(cnt[e[j]]>=n-1)return -1;
            }
        }

    }
    return 0;
}
int main(){
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }

    if(spfa()==-1)cout<<"Yes";
    else cout<<"No";

}

floyd算法 题目:Floyd求最短路

#include<iostream>
using namespace std;
int s[210][210];
int n,m,q;
void floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                s[i][j]=min(s[i][j],s[i][k]+s[k][j]);
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(i==j)s[i][j]=0;
            else s[i][j]=1e9;
        }
    for(int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(z<s[x][y])s[x][y]=z;
    }
    floyd();
    while(q--){
        int x,y;
        scanf("%d%d",&x,&y);
        if(s[x][y]>1e9 / 2)printf("impossible\n");
        else printf("%d\n",s[x][y]);
    }
}

网上找的floyd判断是否有负环

for(int i = 1; i <=n ; i++)
		if(d[i][i] < 0) return true;
	return false; 

今日练习的挺少的,应该多抄抄模板,刚开始学前两个最短路还挺清晰,现在学多了全都记不太清是啥了

明日任务:多熟悉这两天学的求最短路问题的模板,给搜索与图论(3)开头

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值