2022/2/18

142 篇文章 0 订阅
142 篇文章 1 订阅
本文整理了多种图论算法模板,包括迪杰斯特拉算法(Dijkstra)、无向图割边模板、SPFA(Shortest Path Faster Algorithm)算法以及Floyd沃斯算法,涵盖了寻找最短路径和图的割边问题。这些模板适用于解决复杂网络中的路径优化和网络连接稳定性分析。
摘要由CSDN通过智能技术生成

从今天开始做最短路!

p4779 迪杰斯特拉模板

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll cnt,n,m,s,head[2000005],dist[2000005],vis[2000005],pre[2000005];
struct Edge{
    ll to,dis,next;
}edge[2000005];
void Add_edge(ll from,ll to,ll w){
    edge[++cnt].to=to;
    edge[cnt].dis=w;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
struct node{
    ll id,dis;
    bool operator<(const node &a)const{
        return a.dis<dis;
    }
};
void print_path(ll s,ll t){
    if(s==t){printf("%lld ",s);return;}
    print_path(s,pre[t]);
    printf("%d ",t);
}
void dij(){
    priority_queue<node>q;
    q.push(node{s,0});
    for(int i=1;i<=n;i++) dist[i]=inf;
    dist[s]=0;
    while(!q.empty()){
        node a=q.top();q.pop();
        ll now=a.id;
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=head[now];i;i=edge[i].next){
            ll j=edge[i].to;
            if(dist[now]+edge[i].dis<dist[j]){
                dist[j]=dist[now]+edge[i].dis;
                if(!vis[j]) q.push(node{j,dist[j]});
                pre[j]=a.id;
            }
        }
    }
    //print_path(s,n);
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld%lld%lld",&n,&m,&s);
    for(int i=1;i<=m;i++){
        ll a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        Add_edge(a,b,c);
        //Add_edge(b,a,c);
    }
    dij();
    for(int i=1;i<=n;i++)
        cout<<dist[i]<<" ";
    return 0;
}

p1656 无向图求割边 模板

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll n,m,a,b,head[10005],ct,cnt,low[100005],num[100005],dfn;
struct Edge{
    ll to,dis,next;
}edge[100005];
void Add_edge(ll from,ll to){
    edge[++cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
struct node{
    ll s,e;
    bool operator<(const node &a)const{
    if(a.s==s) return a.e>e;
    return a.s>s;
    }
}ans[100005];
void dfs(ll u,ll fa){
    low[u]=num[u]=++dfn;
    for(int i=head[u];i;i=edge[i].next){
        ll v=edge[i].to;
        if(!num[v]){
            dfs(v,u);
            low[u]=min(low[v],low[u]);
            if(low[v]>num[u]){
                if(u>v)ans[++ct].s=v,ans[ct].e=u;
                else ans[++ct].s=u,ans[ct].e=v;
            }
        }
        else if(num[v]<num[u]&&v!=fa)
            low[u]=min(low[u],num[v]);
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&a,&b);
        Add_edge(a,b);
        Add_edge(b,a);
    }
    dfs(1,-1);
    sort(ans+1,ans+ct+1);
    for(int i=1;i<=ct;i++)
        cout<<ans[i].s<<" "<<ans[i].e<<endl;
    return 0;
}

p2648 spfa 超级源

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x3f3f3f3f;
using namespace std;
ll D,P,C,F,S,head[10005],dist[1005],vis[1005],cnt,neg[10005];
struct Edge{
    ll to,next,dis;
}edge[10005];
void addedge(ll from,ll to,ll w){
    edge[++cnt].to=to;
    edge[cnt].dis=w;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
int spfa(ll s){
    memset(neg,0,sizeof(neg));
    neg[s]=1;
    for(int i=1;i<=C;i++) dist[i]=inf,vis[i]=0;
    dist[s]=0;
    queue<ll>q;
    q.push(S);
    vis[s]=1;
    while(!q.empty()){
        ll u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=edge[i].next){
            ll v=edge[i].to,w=edge[i].dis;
            if(dist[u]+w<dist[v]){
                dist[v]=dist[u]+w;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                    neg[v]++;
                    if(neg[v]>=C+1) return 1;//松弛操作最多做n+1次,因为加了个超级源,操作变多
                }
            }
        }
    }
    return 0;
}
int main(){
  // freopen("in.txt","r",stdin);
	scanf("%lld%lld%lld%lld",&D,&P,&C,&F);
	for(int i=1;i<=P;i++){
        ll u,v;
        scanf("%lld%lld",&u,&v);
        addedge(u,v,-D);
	}
	for(int i=1;i<=F;i++){
        ll u,v,w;
        scanf("%lld%lld%lld",&u,&v,&w);
        addedge(u,v,w-D);
	}
	S=C+1;//增加了超级源,避免每个点都搜一遍
	for(int i=1;i<=C;i++) addedge(S,i,0);
	int flag=spfa(S);
	if(flag){printf("orz");return 0;}
	else {
        ll minn=inf;
        for(int i=1;i<=C;i++){
            if(i==S) continue;
            minn=min(minn,dist[i]);
        }
        if(minn>0){cout<<D<<endl;return 0;}
        printf("%lld",-1*minn+D);
	}
}

p1938 spfa板子

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x3f3f3f3f;
using namespace std;
ll D,P,C,F,S,head[10005],dist[1005],vis[1005],cnt,neg[10005];
struct Edge{
    ll to,next,dis;
}edge[10005];
void addedge(ll from,ll to,ll w){
    edge[++cnt].to=to;
    edge[cnt].dis=w;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
int spfa(ll s){
    memset(neg,0,sizeof(neg));
    neg[s]=1;
    for(int i=1;i<=C;i++) dist[i]=inf,vis[i]=0;
    dist[S]=0;
    queue<ll>q;
    q.push(S);
    vis[S]=1;
    while(!q.empty()){
        ll u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=edge[i].next){
            ll v=edge[i].to,w=edge[i].dis;
            if(dist[u]+w<dist[v]){
                dist[v]=dist[u]+w;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                    neg[v]++;
                    if(neg[v]>=C) return 1;//松弛操作最多做n-1次
                }
            }
        }
    }
    return 0;
}
int main(){
   //freopen("in.txt","r",stdin);
	scanf("%lld%lld%lld%lld%lld",&D,&P,&C,&F,&S);
	for(int i=1;i<=P;i++){
        ll u,v;
        scanf("%lld%lld",&u,&v);
        addedge(u,v,-D);
	}
	for(int i=1;i<=F;i++){
        ll u,v,w;
        scanf("%lld%lld%lld",&u,&v,&w);
        addedge(u,v,w-D);
	}
	int flag=spfa(S);
	if(flag){printf("-1");return 0;}
	else {
        ll minn=inf;
        for(int i=1;i<=C;i++){
            if(i==S) continue;
            minn=min(minn,dist[i]);
        }
        if(minn>0){cout<<D<<endl;return 0;}
        printf("%lld",-1*minn+D);
	}
}

p3905 floyd打印路径模板

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,s,t,u[11000],v[11000],path[110][110],w[11000],d,a[11000],b[11000],gra[110][110];
ll vis[110][110];
void floyed(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        if(gra[i][j]==inf) path[i][j]=-1;
        else path[i][j]=j;
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
        if(gra[i][k]!=inf)
        for(int j=1;j<=n;j++)
    if(gra[i][j]>gra[i][k]+gra[k][j]){
        gra[i][j]=gra[i][k]+gra[k][j];
        path[i][j]=path[i][k];
    }
}
int main() {
    //freopen("in.txt","r",stdin);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        if(i==j) gra[i][j]=0;
        else gra[i][j]=inf;
    for(int i=1;i<=m;i++){
        scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);
        gra[u[i]][v[i]]=w[i];
        gra[v[i]][u[i]]=w[i];
    }
    floyed();
    scanf("%lld",&d);
    for(int i=1;i<=d;i++) scanf("%lld%lld",&a[i],&b[i]),vis[a[i]][b[i]]=1,vis[b[i]][a[i]]=1;
    scanf("%lld%lld",&s,&t);
    vector<ll>v;
    v.push_back(s);
    ll tmp=s;
    while(tmp!=t){
        v.push_back(path[tmp][t]);
        tmp=path[tmp][t];
    }
    v.push_back(t);
    ll sum=0;
    for(int i=1;i<v.size();i++){
        if(vis[v[i-1]][v[i]])
            sum+=gra[v[i-1]][v[i]];
    }
    printf("%lld",sum);
	return 0;
}

p5651 bfs

根据异或的自反性(axor a=0),我们发现,从一个点u抵达另一个点v,不管走那条路,它最后的贡献值都是一样的。所谓的最短路只是一个幌子,其实每两个点的距离就只有唯一解。

题解 P5651 【基础最短路练习题】 - 月离 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,cnt,m,q,head[2000005],dist[2000005],vis[2000005];
struct Edge{
    ll to,dis,next;
}edge[2000005];
void addedge(ll from,ll to,ll dis){
    edge[++cnt].dis=dis;
    edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
void bfs(ll s){
    queue<ll>q;
    for(ll i=1;i<=n;i++){
        dist[i]=0;vis[i]=0;
    }
    q.push(s);
    while(!q.empty()){
        ll now=q.front();q.pop();
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=head[now];i;i=edge[i].next){
            ll v=edge[i].to,w=edge[i].dis;
            if(!vis[v]){
                dist[v]=dist[now]^w;
                q.push(v);
            }
        }
    }
}
int main() {
    //freopen("in.txt","r",stdin);
   scanf("%lld%lld%lld",&n,&m,&q);
   for(int i=1;i<=m;i++){
    ll a,b,c;
    scanf("%lld%lld%lld",&a,&b,&c);
    addedge(a,b,c);
    addedge(b,a,c);
   }
   bfs(1);
    for(int i=1;i<=q;i++){
        ll a,b;
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",dist[a]^dist[b]);
    }
	return 0;
}

p6464 Floyd

修改其中的一条路径只需要n的二次方就可以了,不需要3次方

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,gra[210][210],g[210][110],a[2100],b[21000],c[21000];
void floyd(){
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
        if(gra[i][k]!=inf)
        for(int j=1;j<=n;j++)
        if(gra[i][j]>gra[i][k]+gra[k][j])
        gra[i][j]=gra[i][k]+gra[k][j];
}
int main() {
    //freopen("in.txt","r",stdin);
   scanf("%lld%lld",&n,&m);
   for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    gra[i][j]=inf;
   for(int i=1;i<=m;i++){
    scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
    gra[a[i]][b[i]]=c[i];
    gra[b[i]][a[i]]=c[i];
   }
   floyd();
   ll minn=inf;
   for(int i=1;i<=n;i++)
   for(int j=1;j<=n;j++){
    for(int x=1;x<=n;x++)
        for(int y=1;y<=n;y++)
        g[x][y]=gra[x][y];
    g[i][j]=g[j][i]=0;
    for(int x=1;x<=n;x++)
        for(int y=1;y<=n;y++)
        if(g[x][y]>g[x][i]+g[i][y])
        g[x][y]=g[x][i]+g[i][y];
    for(int x=1;x<=n;x++)
        for(int y=1;y<=n;y++)
        if(g[x][y]>g[x][j]+g[j][y])
        g[x][y]=g[x][j]+g[j][y];
        ll sum=0;
        for(int x=1;x<=n;x++)
            for(int y=x+1;y<=n;y++)
            if(g[x][y]!=inf)
            sum+=g[x][y];
        minn=min(minn,sum);
   }
   printf("%lld",minn);
	return 0;
}

p6833 bfs求最短路

求出每个点到这三个地方的最短路径(也就是bfs三遍)然后遍历取最小值就行,ans初始值要大

题解 P6833 【[Cnoi2020]雷雨】 - fanglong 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll dx[4]={-1,1,0,0},dy[4]={0,0,1,-1};
ll n,m,a,b,c,g[1005][1005],dist[3][1005][1005];
struct  node{
    ll x,y,w;
    bool operator<(const node &a)const{
    return a.w<w;
    }
};
void bfs(ll k,ll sx,ll sy){//计算每个点对该点的最短路
    priority_queue<node>q;
    q.push(node{sx,sy,g[sx][sy]});
    bool vis[1005][1005]={0};
    for(int i=1;i<=1000;i++)
        for(int j=1;j<=1000;j++) dist[k][i][j]=1e18;
        dist[k][sx][sy]=g[sx][sy];
    while(!q.empty()){
        ll x=q.top().x,y=q.top().y;q.pop();
        if(vis[x][y]) continue;
        vis[x][y]=1;
        for(int i=0;i<4;i++){
            ll tx=x+dx[i],ty=y+dy[i];
            if(tx<1||tx>n||ty<1||ty>m) continue;
            if(dist[k][tx][ty]>dist[k][x][y]+g[tx][ty]){
                dist[k][tx][ty]=dist[k][x][y]+g[tx][ty];
                q.push(node{tx,ty,dist[k][tx][ty]});
            }
        }
    }
}
int main() {
   // freopen("in.txt","r",stdin);
    scanf("%lld%lld%lld%lld%lld",&n,&m,&a,&b,&c);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) scanf("%lld",&g[i][j]);
    bfs(0,1,a);bfs(1,n,b);bfs(2,n,c);
    ll ans=1e18;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        ans=min(ans,dist[0][i][j]+dist[1][i][j]+dist[2][i][j]-2*g[i][j]);
    printf("%lld",ans);
	return 0;
}

p1073 bfs

题解 P1073 【最优贸易】 - saxiy's blog QωQ。。 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,v[100005],minv[100005],maxv[100005];
ll sa[100005],ans;
queue<ll>q;
struct gra{
    ll head[100005],to[1000006],next[1000006],cnt=0;
    bool vis[100005];
    void addedge(ll u,ll v){
    to[++cnt]=v;
    next[cnt]=head[u];
    head[u]=cnt;
    }
    void bfs(ll s){
    vis[s]=1;q.push(s);
    while(!q.empty()){
        ll p=q.front();q.pop();
        for(int i=head[p];i;i=next[i]){
            if(!vis[to[i]])
                vis[to[i]]=1,q.push(to[i]);
        }
    }
    }
    void mark(ll s,ll *a,ll v){
    a[s]=v;q.push(s);
    while(!q.empty()){
        ll p=q.front();q.pop();
        for(int i=head[p];i;i=next[i]){
            if(!a[to[i]])
                a[to[i]]=v,q.push(to[i]);
        }
    }
    }
}mp,fmp;
bool cmp(ll a,ll b){
    return v[a]<v[b];
}
int main() {
    //freopen("in.txt","r",stdin);
    scanf("%lld%lld",&n,&m);
    ll a,b,op;
    for(int i=1;i<=n;i++)
        scanf("%lld",&v[i]);
    while(m--){
        scanf("%lld%lld%lld",&a,&b,&op);
        mp.addedge(a,b);
        fmp.addedge(b,a);
        if(op==2){
            mp.addedge(b,a);
            fmp.addedge(a,b);
        }
    }
    mp.bfs(1);fmp.bfs(n);
    for(int i=1;i<=n;i++) sa[i]=i;
    sort(sa+1,sa+n+1,cmp);
    for(int i=1;i<=n;i++)
        if(!minv[sa[i]]&&mp.vis[sa[i]])
        mp.mark(sa[i],minv,v[sa[i]]);
    for(int i=n;i>=1;i--)
        if(!maxv[sa[i]]&&fmp.vis[sa[i]])
        fmp.mark(sa[i],maxv,v[sa[i]]);
    for(int i=1;i<=n;i++)
        if(mp.vis[i]&&fmp.vis[i])
        ans=max(ans,maxv[i]-minv[i]);
    printf("%lld",ans);
	return 0;
}

p1119 floyd

floyd三重循环的第一重是有意义的,是i和j之间允许那几个点作为中转点以使i和j的距离能够更短,那这题不就很好的体现了这个吗,那个村庄建好了,那个就被允许作为中转点了,然后进行一遍转移,之后在看看x,y之间有没有最短的路径就行了

题解 P1119 【灾后重建】 - Time_Rune 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
const ll inf=0x7fffffff;
using namespace std;
ll n,m,a[210],u,v,w,q,x,y,t,gra[210][210];
void floyd(ll k){
        for(int i=1;i<=n;i++)
        if(gra[i][k]!=inf)
        for(int j=1;j<=n;j++)
        if(gra[i][j]>gra[i][k]+gra[k][j])
        gra[i][j]=gra[i][k]+gra[k][j];
}
int main() {
    //freopen("in.txt","r",stdin);
   scanf("%lld%lld",&n,&m);
   for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
   for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++) gra[i][j]=inf;
   for(int i=1;i<=m;i++){
    scanf("%lld%lld%lld",&u,&v,&w);
    u++;v++;
    gra[u][v]=w;
    gra[v][u]=w;
   }
   scanf("%lld",&q);
   ll now=1;
   while(q--){
    scanf("%lld%lld%lld",&x,&y,&t);
    while(a[now]<=t&&now<=n){
        floyd(now);
        now++;
    }
    x++;y++;
    if(a[x]>t||a[y]>t) printf("-1\n");
    else if(gra[x][y]==inf) printf("-1\n");
    else printf("%lld\n",gra[x][y]);
   }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值