首页 > 其他 > 详细

图论模板

时间:2019-04-07 20:14:17      阅读:179      评论:0      收藏:0      [点我收藏+]

今天闲的没事来整理一下图论的模板(某些出自他处)

1、sp的邻接矩阵(adjacency matrix

定义:

  逻辑结构分为两部分:V和E集合。因此,用一个一维数组V(vertex)存放图中所有顶点数据;用一个二维数组E(edge)存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。

代码实现:

//无向图
#include<iostream>
#include<cstring>
using namespace std;

int e,n;
int g[101][101];
int w;

int main() {
    int x,y,z;
    cin>>n>>e;
    memset(g,0,sizeof(g));
    for(int i=1; i<=e; i++) {
        cin>>x>>y>>z;
        g[x][y]=g[y][x]=z;
    }
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            printf("%d ",g[i][j]);
        }
        cout<<endl;
    }
}

2、sp的邻接表(Adjacency list

定义:

  邻接表,存储方法跟树的孩子链表示法相类似,是一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。

  对于无向图来说,使用邻接表进行存储也会出现数据冗余,表头结点A所指链表中存在一个指向C的表结点的同时,表头结点C所指链表也会存在一个指向A的表结点。

  邻接表是图的一种最主要存储结构,用来描述图上的每一个点。对图的每个顶点建立一个容器(n个顶点建立n个容器),第i个容器中的结点包含顶点Vi的所有邻接顶点。实际上我们常用的邻接矩阵就是一种未离散化每个点的边集的邻接表。

  在有向图中,描述每个点向别的节点连的边(点a->点b这种情况)。

  在无向图中,描述每个点所有的边(点a-点b这种情况)

代码实现:

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

struct edge {
    int u,v,w,next;
} edge[10001];

int first[1001],num=0;
int n,m;

void add(int u,int v,int w) {
    num++;
    edge[num].next=first[u];
    edge[num].u=u;
    edge[num].w=w;
    edge[num].v=v;
    first[u]=num;
}


int main() {
    scanf("%d%d",&n,&m);
    int u,v,w;
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    for(int i=1; i<=n; i++) {
        int k=first[i];
        while(k!=0) {
            cout<<edge[k].u<<" "<<edge[k].v<<endl;
            k=edge[k].next;
        }
    }
    return 0;
}

3、sp的深搜遍历(DFS

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

int e[1010][1010];
int vis[1010];
int n,m;

void dfs(int u);

int main() {
    cin>>n>>m;
    char x,y;
    for(int i=1; i<=m; i++) {
        cin>>x>>y;
        e[x-65][y-65]=e[y-65][x-65]=1;
    }
    dfs(0);
    return 0;
}

void dfs(int u) {
    cout<<char(u+65)<<" ";
    vis[u]=1;
    for(int i=1; i<=n; i++) {
        if(e[u][i]==1 && vis[i]==0) {
            dfs(i);
        }
    }
}

4、sp的广搜遍历(BFS

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int e[1010][1010];
int vis[1010],que[1010];
int n,m;

void bfs(int u);

int main() {
    cin>>n>>m;
    char x,y;
    for(int i=1; i<=m; i++) {
        cin>>x>>y;
        e[x-65][y-65]=e[y-65][x-65]=1;
    }
    bfs(0);
    return 0;
}

void bfs(int u) {
    int h=0,t=1;
    que[t]=u;
    cout<<char(u+65)<<" ";
    vis[u]=1;
    while(h<t) {
        h++;
        int k=que[h];
        for(int i=1; i<=n; i++) {
            if(e[k][i]==1 && vis[i]==0) {
                t++;
                cout<<char(i+65)<<" ";
                vis[i]=1;
                que[t]=i;
            }
        }
    }
}

5、spfloyed算法

原理:

  利用邻接矩阵判断

步骤:

  1.把所有的边赋值无穷大,能通过的赋值

  2. 三个for循环,k,i,j,  k表示从i->j可以走i->k->j,不断取小值

  3.选取出发点和结束点,直接输出就是最短路

代码实现:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int  MAX = 300;
const int inf = 0x3f3f3f3f;
int d[MAX],ditu[MAX][MAX];
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n ; i++)
        for(int j = 1; j <= n; j++)
            ditu[i][j] = inf;
    int x, y, t;
    for(int i = 1; i <=m; i++) {
        scanf("%d%d%d",&x,&y,&t);
        ditu[x][y] = t;
    }
    for(int k = 1; k <= n ; k++) {
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(i!=k && i!=j && ditu[i][j]>ditu[i][k]+ditu[k][j])
                    ditu[i][j] = ditu[i][k]+ditu[k][j];
            }
        }
    }
    printf("%d",ditu[1][n]);
    return 0;
}

然后我们可以进行两个优化

(1)、剪枝:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
int qread() {
    int x=0;
    char ch=getchar();
    while(ch<0||ch>9)ch=getchar();
    while(ch>=0&&ch<=9) {
        x=x*10+ch-0;
        ch=getchar();
    }
    return x;
}
template<typename T>inline void write(T x) {
    if(x<0)putchar(-),x*=-1;
    if(x>=10)write(x/10);
    putchar(x%10+0);
}
int dis[1010][1010];
int main() {
    int n,m,a,b,s;
    cin>>n>>m;
    for(int i=1; i<=m; ++i) {
        a=qread();
        b=qread();
        s=qread();
        dis[a][b]=dis[b][a]=s;
    }
    for(int k=1; k<=n; ++k)
        for(int i=1; i<=n; ++i)
            if(i!=k) {
                for(int j=1; j<=i; ++j) {
                    if(i!=j&&j!=k&&dis[i][j]>dis[i][k]*dis[k][j]&&dis[i][k]!=0&&dis[k][j]!=0) {
                        dis[i][j]=dis[i][k]*dis[k][j];
                        dis[i][j]%=9987;
                        dis[j][i]=dis[i][j];
                    }
                }
            }
    write(dis[1][n]);
    return 0;
}

(2)、判断

#include<bits/stdc++.h>
using namespace std;
long long g[1010][1010];
long long n,m,a,b,s;

int qread()
{
    int 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;
}

int main() {
    n=qread();m=qread();
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            g[i][j]=0xffffff;
        }
    }
    for(int i=1; i<=m; i++) {
        a=qread();b=qread();s=qread();
        g[a][b]=s;
    }
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            if(i!=k && g[i][k]!=0xffffff) {
                for(int j=1; j<=n; j++) {
                    if(i!=j&&j!=k&&g[i][j]>g[i][k]*g[k][j]) {
                        g[i][j]=g[i][k]*g[k][j];
                    }
                }
            }
    printf("%lld",g[1][n]%9987);
    return 0;
}

插一句,一起食用更佳哦

 

6、spDijkstra算法

  Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。

代码实现:

//Dijkstra
#include<iostream>
#include<cstdio>
#define INF 9999999
using namespace std;


const int maxn=1010;
int dis[maxn];//储存单源最短路径 
int w[maxn][maxn];//初始储存两点之间是否有路径 
int f[maxn]= {0};
int n,m,s;
int x,y,z;

//输入及初步处理 
void work() {
    cin>>n>>m>>s;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            if(j==i)w[i][j]=0;//自己到自己的路径是0 
            else w[i][j]=INF;//否则初始化为最大值 
        }
    }
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&x,&y,&z);//分别代表x到y之间有边,权值为z 
        w[x][y]=z;//无向图的话 
        w[y][x]=z;
    }
    for(int i=1; i<=n; i++) {
        dis[i]=w[s][i];//有路径呗 
        f[i]=0;
    }
}

//迪杰斯特拉算法求单源最短路径
//这就是模板啦!! 
//木啥好说的 
void dijkstra() {
    dis[s]=0;
    f[s]=1;
    for(int i=1; i<=n; i++) {
        int mind=INF;
        int k;
        for(int j=1; j<=n; j++) {
            if(dis[j]<mind && !f[j]) {
                mind=dis[j];
                k=j;
            }
        }
        if(mind==INF)break;//这里我经常忘记恒等于号,错了好几遍
        f[k]=1;
        for(int j=1; j<=n; j++) {
            if(dis[j]>dis[k]+w[k][j]) {
                dis[j]=dis[k]+w[k][j];
            }
        }
    }
}

//输出函数
void write() { 
    for(int i=1; i<=n; i++) {
        cout<<dis[i]<<" ";
    }
}

int main() {
    work();
    dijkstra();
    write();
    return 0;
}

可以进行堆优化

#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue> 
using namespace std;
typedef pair<int,int> pairs;
priority_queue<pairs,vector<pairs>,greater<pairs> >q ;
int dis[100007],head[100007];
bool vis[100007];
int n,m,s,t,cnt;
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch))f|=ch==-,ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return f?-x:x;
}
struct Edge{
    int next,to,w;
}edge[100007];
void add_edge(int from,int to,int w){
    edge[++cnt].next=head[from];edge[cnt].w=w;
    edge[cnt].to=to;head[from]=cnt;
}
inline void dijkstra(){
    memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    q.push(make_pair(dis[s],s));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(dis[x]+edge[i].w<dis[to]){
                dis[to]=dis[x]+edge[i].w;
                q.push(make_pair(dis[to],to));
            }
        }
    }
}

int main(){
    n=read(),m=read(),s=read();
    for(int i=1;i<=m;++i){
        int u=read(),v=read(),w=read();
        add_edge(u,v,w);
    }
    dijkstra();
    for(int i=1;i<=n;++i)printf("%d ",dis[i]);
    return 0;
}

 

图论模板

原文:https://www.cnblogs.com/loceaner/p/10666658.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!