最短路,最小生成树,及拓扑排序模板整理

来源:互联网 发布:linux查cpu核数 编辑:程序博客网 时间:2024/05/01 18:42

最短路,最小生成树,及拓扑排序都是图论基础算法,这里不再赘述,只进行模板整理,如有疑问还请评论留言
对于最短路算法,这里除常用的SPFA和堆优化Dijkstra外,还整理了许多学校和算法竞赛培训机构不会教授的Bellman_ford与原版Dijkstra,以便于读者理解前面的两种优化版本。

最短路:

最短路算法经典例题
http://codevs.cn/problem/1557/热浪

//Bellman_ford版本#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>const int INF=100000000; using namespace std;int t,c,ts,te,cnt;int u[100000],v[100000],d[100000],w[100000];void Bellman_ford(){    for(int i=1;i<=t;i++)    d[i]=INF;    d[ts]=0;    for(int i=1;i<=t-1;i++)    for(int j=1;j<=cnt;j++)    {        if(d[u[j]]<INF)        d[v[j]]=min(d[v[j]],d[u[j]]+w[j]);    }}int main(){    scanf("%d%d%d%d",&t,&c,&ts,&te);    cnt=c;    for(int i=1;i<=c;i++)    {        scanf("%d%d%d",&u[i],&v[i],&w[i]);        u[++cnt]=v[i];        v[cnt]=u[i];        w[cnt]=w[i];    }    Bellman_ford();    printf("%d",d[te]);    return 0;}



//SPFA邻接链表版本//SPFA是Bellman_ford的队列优化#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<queue>using namespace std;const int INF=1000000000;int t,c,ts,te,ru,rv,rw,tot,x;int d[100000],first[100000],next[100000];bool inq[100000];queue<int>q;struct Edge{    int u,v,w;}l[100000];void build(int u,int v,int w){    l[++tot]=(Edge){u,v,w};    next[tot]=first[u];    first[u]=tot;}void SPFA(){    for(int i=1;i<=t;i++)    d[i]=INF;    d[ts]=0;    inq[ts]=1;    q.push(ts);    while(!q.empty())    {        int k=q.front();        q.pop();        inq[k]=0;        for(int i=first[k];i!=-1;i=next[i])        {            x=l[i].v;            if(d[k]<INF&&d[x]>d[k]+l[i].w)            {                d[x]=d[k]+l[i].w;                if(!inq[x])                q.push(x);                inq[x]=1;            }        }    }}int main(){    memset(first,-1,sizeof(first));    scanf("%d%d%d%d",&t,&c,&ts,&te);    for(int i=1;i<=c;i++)    {        scanf("%d%d%d",&ru,&rv,&rw);        build(ru,rv,rw);        build(rv,ru,rw);    }    SPFA();    printf("%d",d[te]);    return 0;}



//SPFA邻接表版本#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<queue>#include<vector>using namespace std;const int INF=1000000000;int t,c,ts,te,ru,rv,rw,tot,x,w;int d[100000];bool inq[100000];vector<int>G[100000];vector<int>V[100000];queue<int>q;inline void build(int u,int v,int w){     G[u].push_back(v);     V[u].push_back(w);     G[v].push_back(u);     V[v].push_back(w);}void SPFA(){    for(int i=1;i<=t;i++)    d[i]=INF;    d[ts]=0;    inq[ts]=1;    q.push(ts);    while(!q.empty())    {        int k=q.front();        q.pop();        inq[k]=0;        for(int i=0;i<G[k].size();i++)        {            x=G[k][i];            w=V[k][i];            if(d[k]<INF&&d[x]>d[k]+w)            {                d[x]=d[k]+w;                if(!inq[x])                q.push(x);                inq[x]=1;            }        }    }}int main(){    scanf("%d%d%d%d",&t,&c,&ts,&te);    for(int i=1;i<=c;i++)    {        scanf("%d%d%d",&ru,&rv,&rw);        build(ru,rv,rw);    }    SPFA();    printf("%d",d[te]);    return 0;}



//Dijkstra版本#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;const int INF=1000000000;int t,c,ts,te,x,y,r;int d[1000001];int w[2500][2500]; bool v[1000001];void dijkstra(){    for(int i=1;i<=t;i++)    d[i]=INF;    d[ts]=0;    for(int i=1;i<=t;i++)    {        int k=0,m=INF;        for(int j=1;j<=t;j++)        {            if(!v[j]&&d[j]<=m)            {                m=d[j];                k=j;            }        }        v[k]=1;        for(int j=1;j<=t;j++)        if(!v[j])        d[j]=min(d[j],d[k]+w[k][j]);    }}int main(){    scanf("%d%d%d%d",&t,&c,&ts,&te);    for(int i=1;i<=t;i++)    for(int j=1;j<=t;j++)    {        if(i!=j)        w[i][j]=INF;    }    for(int i=1;i<=c;i++)    {        scanf("%d%d%d",&x,&y,&r);        w[x][y]=w[y][x]=r;    }    dijkstra();    printf("%d",d[te]);    return 0;}



//Dijkstra,堆优化,邻接链表版本#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int MAXN = 100000 + 5;int t,c,ts,te,tot,rs,re,rc;int dis[MAXN],first[MAXN],next[MAXN];bool done[MAXN];struct edge{    int f,t,v;}l[MAXN << 1];struct zt{    int num;    int d;//距离用于排序     /*bool operator < (zt a)const    {        return d>a.d;       }    friend bool operator < (zt a,zt b)    {        return a.d<b.d;    }*///2种写法,仅对结构体里的小于号生效}p[MAXN];priority_queue<zt>q;bool operator < (zt a,zt b){    return a.d>b.d;}void build(int f,int t,int v){    l[++tot]=(edge){f,t,v};    next[tot]=first[f];    first[f]=tot;}void dijkstra(){    while(!q.empty()) q.pop();    q.push((zt){ts,0});    dis[ts]=0;    while(!q.empty())    {        zt a=q.top();        int u=a.num;        q.pop();        if(done[u]==1)        continue;        done[u]=1;        for(int i=first[u];i!=-1;i=next[i])        {            int v=l[i].t;            if(dis[v]>dis[u]+l[i].v)            {                dis[v]=dis[u]+l[i].v;                q.push((zt){v,dis[v]});            }        }    }}int main(){    memset(dis,0x3f,sizeof(dis));    memset(first,-1,sizeof(first));    scanf("%d%d%d%d",&t,&c,&ts,&te);    for(int i=1;i<=c;i++)    {        scanf("%d%d%d",&rs,&re,&rc);        build(rs,re,rc);        build(re,rs,rc);    }    dijkstra();    printf("%d",dis[te]);    return 0;}



http://codevs.cn/problem/1021/玛丽卡
对答案有贡献的路径只存在于最短路上
先跑一边SPFA找出最短路上的边,依次尝试删除每条边,跑SPFA统计答案即可

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>using namespace std;const int INF = 1000000007;int n,m,ru,rv,rw,tot,ans;int dis[500010],first[1000010],nxt[1000010],pre[500010];bool flag;bool inq[100010];struct edge{    int u,v,w;}l[1000010];queue<int>q;void build(int f,int t,int c){    l[++tot]=(edge){f,t,c};    nxt[tot]=first[f];    first[f]=tot;}void SPFA(int l1,int l2){    for(int i=1;i<=n;i++)    dis[i]=INF;    dis[1]=0;    q.push(1);    inq[1]=1;    while(!q.empty())    {        int k=q.front();        q.pop();        inq[k]=0;        for(int i=first[k];i!=-1;i=nxt[i])        {            int x=l[i].v;            if((k==l1&&x==l2)||(k==l2&&x==l1))            continue;            if(dis[x]>dis[k]+l[i].w)            {                dis[x]=dis[k]+l[i].w;                if(!flag)                pre[x]=k;                if(!inq[x])                {                    q.push(x);                    inq[x]=1;                }            }        }    }}int main(){    memset(first,-1,sizeof(first));    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    {        scanf("%d%d%d",&ru,&rv,&rw);        build(ru,rv,rw);        build(rv,ru,rw);    }    tot=0;    SPFA(0,0);    flag=1;    for(int i=n;i;i=pre[i])    {        SPFA(i,pre[i]);        ans=max(ans,dis[n]);    }    printf("%d",ans);    return 0;}


最小生成树:

http://codevs.cn/problem/1231/最优布线问题

//Kruskal版本#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>using namespace std;typedef unsigned long long LL;int n,m,cnt,x,y,e;int u[1000000],v[1000000],w[1000000],r[1000000],fa[1000000];LL cost;bool cmp(int a,int b){    return w[a]<w[b];}int find(int x){    return fa[x]==x?x:fa[x]=find(fa[x]);}void kruskal(){    for(int i=1;i<=n;i++)    fa[i]=i;    for(int i=1;i<=m;i++)    r[i]=i;    sort(r+1,r+m+1,cmp);    for(int i=1;i<=m;i++)    {        e=r[i];        x=find(u[e]);        y=find(v[e]);        if(x!=y)        {            cost+=w[e];            fa[x]=y;        }    }}int main(){    scanf("%d%d",&n,&m);    cnt=n;    for(int i=1;i<=m;i++)    {        scanf("%d%d%d",&u[i],&v[i],&w[i]);    }    kruskal();    printf("%lld",cost);    return 0;}



//Prim#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<queue>using namespace std;typedef unsigned long long LL;const int MAXN=1000000;LL n,m,rf,rt,rv,tot,cost,cnt;LL first[MAXN],next[MAXN];bool done[MAXN];struct Edge{    LL f,t,v;}l[MAXN];struct condition {    LL num,d;}p[MAXN];priority_queue<condition>q;bool operator < (condition a,condition b){    return a.d>b.d;}void build(int f,int t,int v){    l[++tot]=(Edge){f,t,v};    next[tot]=first[f];    first[f]=tot;}void prim(){    while(!q.empty()) q.pop();    q.push((condition){1,0});    while(!q.empty()&&cnt<n)    {        condition a=q.top();        LL u=a.num;        LL w=a.d;        q.pop();        if(done[u])        continue;        done[u]=1;        cost+=w;        cnt++;        for(int i=first[u];i!=-1;i=next[i])        if(!done[l[i].t])        q.push((condition){l[i].t,l[i].v});    }}int main(){    memset(first,-1,sizeof(first));    scanf("%lld%lld",&n,&m);    for(int i=1;i<=m;i++)    {        scanf("%lld%lld%lld",&rf,&rt,&rv);        build(rf,rt,rv);        build(rt,rf,rv);    }    prim();    printf("%lld",cost);    return 0;}


拓扑排序:

http://codevs.cn/problem/2833/奇怪的梦境

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>using namespace std;queue<int>q;int n,m,ru,rv,tot,cnt,fla;int first[100001],next[100001],pas[100001],ans[100001],jud1[100001],jud2[100001];bool flag;struct spot{    int u,v;}l[100001];void build(int f,int t){    l[++tot]=(spot){f,t};    next[tot]=first[f];    first[f]=tot;}int main(){    memset(first,-1,sizeof(first));    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    {        scanf("%d%d",&ru,&rv);        if(jud1[ru]==rv)        continue;        pas[rv]++;        jud1[ru]=rv;        build(ru,rv);    }    for(int i=1;i<=n;i++)    if(pas[i]==0)    q.push(i);    while(!q.empty())    {        int x=q.front();        q.pop();        ans[++cnt]=x;        for(int i=first[x];i!=-1;i=next[i])        {            pas[l[i].v]--;            if(pas[l[i].v]==0)            q.push(l[i].v);        }    }    if(cnt>=n)    printf("o(∩_∩)o");    else    {        printf("T_T\n");        printf("%d",n-cnt);    }    return 0;}
原创粉丝点击