图论算法

并查集

int fa[MAX];

void init(){
  for(int i=0;i<MAX;i++)fa[i]=i;
}

int find(int i){
  int temp=i;
  while(temp!=fa[temp])temp=fa[temp];
  if(temp!=i){
    int t=fa[i];
    fa[i]=temp;
    i=t;
  }
  return temp;
}

void merge(int a,int b){
  fa[a]=b;
}


最小生成树(克鲁斯卡尔)

struct edge {
  int u,v,w;
};

int n,m,a,b,c;
vector<edge> v;

bool cmp(edge a,edge b) {
  return a.w<b.w;
}

int kruskal(){
  init(); // 初始化并查集
  int ans=0;
  sort(v.begin(),v.end(),cmp); // 按照边权值的大小排序
  for(int i=0; i<v.size(); i++) { // 依次选择权值小的边
    int a=find(v[i].u);
    int b=find(v[i].v);
    if(a!=b) { // 判断这两个点是否已经连接
      merge(a,b);
      ans+=v[i].w;
    }
  }
  return ans;
}


最短路(Dijkstra)

int vis[MAX],d[MAX];
int w[MAX][MAX];

// 以邻接矩阵存储图
void dijkstra(){
  memset(vis,0,sizeof(vis)); // 初始化vis数组
  for(int i=1;i<=n;i++)d[i]=w[1][i]; // 初始化到起点的距离
  vis[1]=1;
  for(int i=1;i<=n;i++){
    int minn=INF,k=0;
    for(int j=1;j<=n;j++) // 寻找当前路径最短的点
      if(!vis[j] && d[j]<minn)
        minn=d[j],k=j;
    vis[k]=1;
    for(int j=1;j<=n;j++) // 松弛操作
      if(!vis[j] && minn+w[k][j]<d[j])d[j]=minn+w[k][j];
  }
}


最短路(SPFA)

struct node { // 连接的点和到达该点的时间
  int to,time;
};

vector<node> G[MAX];

int n,m,a,b,c;
int vis[MAX],d[MAX];

// 以邻接表存储图
void spfa() {
  memset(vis,0,sizeof(vis)); // 初始化vis数组
  for(int i=0; i<MAX; i++) d[i]=INF; // 初始化距离最大
  queue<node> q;
  q.push({1,0}); // 起点入列
  vis[1]=1; // 进入队列标志
  d[1]=0; // 起点距离为0
  while(!q.empty()) {
    node u=q.front(); q.pop();
    vis[u.to]=0; // 出队列标志
    for(int i=0; i<G[u.to].size(); i++) { // 遍历所有邻接的点
      node v=G[u.to][i];
      if(d[v.to]>d[u.to]+v.time) { // 松弛操作
        d[v.to]=d[u.to]+v.time;
        if(!vis[v.to]) { // 如果没有入列则入列
          vis[v.to]=1;
          q.push(v);
        }
      }
    }
  }
}


最短路(Floyd)

int w[MAX][MAX];

// 以邻接矩阵存储图
void floyd(){
  for(int k=1;k<=n;k++){ // 作为中间节点
    for(int i=1;i<=n;i++){
      if(w[i][k]!=INF){
        for(int j=1;j<=n;j++){
          w[i][j]=min(w[i][j],w[i][k]+w[k][j]); // 松弛操作
        }
      }
    }
  }
}


拓扑排序

扫描二维码关注公众号,回复: 2116155 查看本文章
int w[MAX][MAX];
int rd[MAX]; // 存储结点的入度
int vis[MAX];
int topo[MAX]; // 拓扑排序后的顺序

// 以邻接矩阵存储图
bool toposort(){
  for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
      if(!vis[j]&&rd[j]==0){ // 没有遍历过且入度为0
        vis[j]=1;
        topo[i]=j;
        for(int k=1;k<=n;k++) // 删除以这个点为弧尾的边,并将入度减1
          if(w[j][k]){w[j][k]=0;rd[k]--;}
        break;
      }
    }
  }
  for(int i=1;i<=n;i++) // 如果有节点没有遍历到,说明有环
    if(!vis[i])return 0;
  return 1;
}


欧拉路径

int g[MAX][MAX]; // 邻接矩阵存储图,元素为结点间边的数量
int d[MAX]; // 存储结点的度
int path[MAX],p=0; // 存储欧拉路径

// 无向图欧拉路径
bool eulor(){
  int cnt=0;
  for(int i=1;i<=n;i++) // 并查集判断图是否连通
    if(fa[i]==i)cnt++;
  if(cnt!=1)return 0;
  cnt=0;
  for(int i=1;i<=n;i++) // 无向图判断是否只有两个度为奇数的结点(欧拉通路)
    if(d[i]%2==1)cnt++; // 或者无度为奇数的结点(欧拉回路)
  if(cnt==0||cnt==2)return 1;
  return 0;
}

// dfs求欧拉路径
void dfs(int start){ // 给予欧拉路径起始点
  for(int j=1;j<=n;j++){
    if(g[start][j]){
      g[start][j]--;g[j][start]--;
      dfs(j);
      if(g[start][j])j--;
    }
  }
  path[p++]=start; // 存储欧拉路径
}



猜你喜欢

转载自blog.csdn.net/zhq9695/article/details/80954606