算法小总结-图论

拓扑排序
[HNOI2015]菜肴制作

//
// Created by fxz on 2024/8/3.
//


#include <bits/stdc++.h>

using namespace  std;


int ans[1008611];
#define int long long


    bool TopSort(vector<vector<int>> &G, int n, vector<int> &inDegree) {
        int cnt=1;
        int num = 0;				//记录加入拓扑排序的顶点数
        priority_queue<int> q;
        for (int i = 1; i <=n; i++)
            if (inDegree[i] == 0)
                q.push(i);		//将所有入度为0的顶点入队
        while (!q.empty()) {
            int u = q.top();		//取队首顶点u
            ans[cnt++]=u;
            q.pop();
            for (int i = 0; i <G[u].size(); i++) {
                int v = G[u][i];		//u的后继节点
                inDegree[v]--;			//v的入度减1
                if (inDegree[v] == 0)		//顶点v的入度减为0则入队
                    q.push(v);
            }
            G[u].clear();			//清空顶点u的所有出边
            num++;
        }
        if (num == n)				//加入拓扑序列的顶点数为n,说明拓扑排序成功,否则,失败
            return true;
        else
            return false;
    }

int32_t main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--) {
        int n,m;
        cin >> n >>m;
        vector<vector<int>> G(n+1);
        for (int i = 1; i <= m; ++i) {
            int a, b;
            cin >> a >> b;
            G[b].push_back(a);
        }
        vector<int> inDegree(n+1);
        for (auto x : G) {
            for (auto y : x)
                inDegree[y]++;
        }
        bool res = TopSort(G, n, inDegree);
        if(res==0)cout<<"Impossible!"<<'\n';
        else {
            for(int i=n;i>=1;i--){
                cout<<ans[i]<<' ';
            }
            cout<<'\n';
        }
    }

    return 0;

}


Dijkstrra
单源最短路,有向图,无向图都可以用,但是必须是无负权边,每个点都会看一遍
模版如下

#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
const int N=1010;
const int M=200010;
int head[N];
int dis[N];
bool vis[N];
int tot;
int n,m,s,t;
struct ty{
    int t,l,next;
}edge[200010];

void add(int x,int y,int z){
    edge[++tot].l=z;
    edge[tot].t=y;
    edge[tot].next=head[x];
    head[x]=tot;
}

struct ty2 {
    int x, dis;
    bool operator<(const ty2 &a) const{
        return dis>a.dis;
    }
};


priority_queue<ty2> q;
void dij(int s,int t)
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof (vis));
    dis[s]=0;
    ty2 tmp;
    tmp.x=s,tmp.dis=0;
    q.push(tmp);

    while(q.size())
    {
        ty2 tmp=q.top();
        q.pop();
        if(vis[tmp.x])continue;
        vis[tmp.x]=1;
        for(int i=head[tmp.x];i!=-1;i=edge[i].next){
            int y=edge[i].t;
            if(dis[y]>dis[tmp.x]+edge[i].l){
                dis[y]=dis[tmp.x]+edge[i].l;
                ty2 tmp2;
                tmp2.x=y,tmp2.dis=dis[y];
                q.push(tmp2);
            }
        }
    }
    if(dis[t]>=0x3f3f3f3f)cout<< -1<<'\n';
    else
        cout<<dis[t]<<'\n';
}

int main()
{
    memset(head,-1,sizeof(head));
    cin>>n>>m>>s>>t;
    for(int i=1;i<=m;i++)
    {
        int x,y,v;
        cin>>x>>y>>v;
        add(x,y,v);
        add(y,x,v);
    }
    dij(s,t);

    return 0;
}

链式前向星
如果说邻接表是不好写但效率好,邻接矩阵是好写但效率低的话,前向星就是一个相对中庸的数据结构。前向星固然好写,但效率并不高。而在优化为链式前向星后,效率也得到了较大的提升。虽然说,世界上对链式前向星的使用并不是很广泛,但在不愿意写复杂的邻接表的情况下,链式前向星也是一个很优秀的数据结构。 ——摘自《百度百科》

#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
const int N=1010;
const int M=20010;
int head[N],e[M],ne[M],w[M];
int dis[N];
bool vis[N];
int tot;
int n,m,s,t;
int x,y,v;

void add(int x,int y,int z)
{
    e[++tot]=y;
    w[tot]=z;
    ne[tot]=head[x];
    head[x]=tot;
}

void dij(int s)
{
    priority_queue<pii> p;
    dis[s]=0;
    p.push({0,s});
    while(p.size())
    {
        int x=p.top().second;
        p.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=ne[i])
        {
            int y=e[i];
            int z=w[i];
            if(dis[y]>dis[x]+z)
            {
                dis[y]=dis[x]+z;
                p.push({-dis[y],y});
            }
        }
    }
}

int main()
{
    memset(dis,0x3f,sizeof(dis));
    cin>>n>>m>>s>>t;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>v;
        add(x,y,v);
        add(y,x,v);
    }
    dij(s);
    if(dis[t]>=0x3f3f3f3f) cout<<-1<<endl;
    else cout<<dis[t]<<endl;

    return 0;
}

Bellman-Ford算法 (需要掌握链式前向星)
暴力做法,解决负权边,但是不能有负环

# include <iostream>
# include <cstdio>
# include <cmath>
# include <cstring>
using namespace std;
# define int long long
# define N 10005
# define M 10005
int s,t,n,m,m2;
double f[N];
struct node{
    int x,y;
}a[N];
struct node2{
    int to,next;
    double w;
}e[M];
int adj[N];
void add(int u,int v,double w2){
    m2++;
    e[m2].to=v;
    e[m2].w=w2;
    e[m2].next=adj[u];
    adj[u]=m2;
    return ;
}
void relax(int u,int v,double w2){
    if (f[v]>f[u]+w2){
        f[v]=f[u]+w2;
    }
    return ;
}
void ford(){
    memset(f,0x7f7f,sizeof(f));
    f[s]=0;
    for (int i=1;i<=n-1;i++){
        for (int j=1;j<=n;j++){
            for (int k=adj[j];k;k=e[k].next){
                int l=e[k].to;
                relax(j,l,e[k].w);
            }
        }
    }
    return ;
}
signed main(){
    ford();
    printf("%.2lf",f[t]);
    return 0;
}

SPFA(贝尔曼-福特算法的优化算法)

#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
const int N=10010;
const int M=200010;
int head[N];
int dis[N];
bool vis[N];
int tot;
int n,m,s,t;
struct ty{
    int t,l,next;
}edge[200010];

void add(int x,int y,int z){
    edge[++tot].l=z;
    edge[tot].t=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
struct ty2 {
    int x, dis;
    bool operator<(const ty2 &a) const{
        return dis>a.dis;
    }
};

queue<int>q1;
void spfa(int s,int t)
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof (vis));
    dis[s]=0;
    vis[s]=1;
   q1.push(s);
   while(q1.size()){
       int x=q1.front();
       q1.pop();
       vis[x]=0;
       for(int i=head[x];i!=-1;i=edge[i].next){
           int y=edge[i].t;
           if(dis[y]>dis[x]+edge[i].l){
               dis[y]=dis[x]+edge[i].l;
               if(!vis[y]){
                   q1.push(y);
                   vis[y]=1;
               }
           }
       }
   }
   if(dis[t]>=0x3f3f3f3f)cout<<-1<<'\n';
   else
       cout<<dis[t]<<'\n';
}

int main()
{
    memset(head,-1,sizeof(head));
    cin>>n>>m>>s>>t;
    for(int i=1;i<=m;i++)
    {
        int x,y,v;
        cin>>x>>y>>v;
        add(x,y,v);
        add(y,x,v);
    }
    spfa(s,t);

    return 0;
}

Floyd

typedef struct          
 2 {        
 3     char vertex[VertexNum];                                //顶点表         
 4     int edges[VertexNum][VertexNum];                       //邻接矩阵,可看做边表         
 5     int n,e;                                               //图中当前的顶点数和边数         
 6 }MGraph; 
 7 
 8 void Floyd(MGraph g)
 9 {
10    int A[MAXV][MAXV];
11    int path[MAXV][MAXV];
12    int i,j,k,n=g.n;
13    for(i=0;i<n;i++)
14       for(j=0;j<n;j++)
15       {   
16              A[i][j]=g.edges[i][j];
17             path[i][j]=-1;
18        }
19    for(k=0;k<n;k++)
20    { 
21         for(i=0;i<n;i++)
22            for(j=0;j<n;j++)
23                if(A[i][j]>(A[i][k]+A[k][j]))
24                {
25                      A[i][j]=A[i][k]+A[k][j];
26                      path[i][j]=k;
27                 } 
28      } 
29 }

posted @ 2024-08-08 19:08  冬天的睡袋  阅读(11)  评论(0编辑  收藏  举报