第三章 搜索与图论(三)(最小生成树,二分图)

news/2024/7/15 17:16:49 标签: 图论, 算法

一、最小生成树算法

稠密图使用prim算法,稀疏图使用kruskal算法

 

   二、prim算法求最小生成树

prim和dijkstra算法类似,都是找到符合某种条件的点,然后更新。prim使用到已经构成的部分最小树所有结点中最小的距离。dijkstra算法是使用到起点最小的距离。

#include<bits/stdc++.h>
//858 prim最小生成树 (稠密图做法)
using namespace std;
const int N=210,INF=0x3f3f3f3f;
int n,m;
int g[N][N];
int dist[N];
bool st[N];
int prim()
{
   int res=0;
   for(int i=0;i<n;i++)
   {
       //找最短的边
       int t=-1;
       for(int j=1;j<=n;j++)
       {
           //只要这个点没有进入集合,或者还没初始化
           //没有进入集合而且边权较少
           if(!st[j]&&(t==-1||dist[t]>dist[j]))
              t=j;
       }
       //如果经过一个循环之后t找到的最短边仍然是INF,但是在第一次的时候所有的都是INF
       if(i&&dist[t]==INF)return INF;
       st[t]=true;
       //由于存在负权自环所以在更新与点相连的所有边之前就保存边
       if(i) res+=dist[t];
       //展示了与dijkstra算法的不同之处,dist保存的是边,而不是某种路
       for(int j=1;j<=n;j++)dist[j]=min(dist[j],g[t][j]);
   }
   return res;
}

int main()
{
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    memset(dist,0x3f, sizeof dist);

    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);
    }
    int ans=prim();
    if(ans==INF)puts("impossible");
    else cout<<ans<<endl;
}

三、kruskal算法

思路简单:

#include<bits/stdc++.h>
//858 prim最小生成树 (稠密图做法)
using namespace std;
const int N=210,INF=0x3f3f3f3f;
int n,m;
int g[N][N];
int dist[N];
bool st[N];
int p[N];
struct Edge
{
    int a,b,w;
    bool operator <(const Edge &W)const
    {
        return w<W.w;
    }
}edges[N];

int find(int a)
{
    if(p[a]==a)return a;
    else  p[a]=find(p[a]); return p[a];
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
      int a,b,c;
      cin>>a>>b>>c;
      edges[i]={a,b,c};
    }
    sort(edges,edges+m);
    for(int i=0;i<=n;i++)p[i]=i;
    int res=0,cnt=0;
    //遍历所有边
    for(int i=0;i<m;i++)
    {
        //访问的顺序是有序的,只要连接的两个点没有在一个连通块里面
        int a=edges[i].a,b=edges[i].b,c=edges[i].w;
        a=find(a),b==find(b);
        if(a!=b)
        {
          p[a]=b;//将其连接
          res+=c;
          cnt++;
        }
    }
    if(cnt!=n-1)puts("impossible");
    else cout<<res<<endl;
}

 四、二分图(染色法判断是否有奇数环)

一个图是二分图当且仅当图中不含有奇数环(环中边的数量是奇数)

如果图当中不含有奇数环染色过程中没有矛盾。

思路:因为有多个连通块,而每次dfs就把连通块里面的所有的点全部遍历了,然后找其他连通块里面的点。

染色法dfs判断奇数环:对于当前点连接的所有边,判断这个点是否已经被染色,没有被染色继续染色,染色了,如果和相连的点的颜色相同,说明有奇数环。

#include<bits/stdc++.h>
//858 prim最小生成树 (稠密图做法)
using namespace std;
const int N=100010,M=200010;
int m,n;
int color[N];//染色情况
int e[N],ne[N],h[N],idx;
void add(int a,int b)
{
    //e保存边idx的终点是什么
    //ne保存idx这条边连接的下一条边
    //更新h的值
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//对一个连通块进行深度优先遍历
bool dfs(int u,int c)
{
   color[u]=c;
   for(int i=h[u];i!=-1;i=ne[i])
   {
       int j=e[i];
       if(!color[j])
       {
           //只要有一个不通就返回false
           if(!dfs(j,3-c))return false;
       }
       else if(color[j]==c)return false;
   }
   return true;

}
int main()
{
    //cmemset(color,0,sizeof color);
    memset(h,-1,sizeof h);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    int flag=0;
    //遍历所有还没有遍历到的连通块,
    for(int i=1;i<=n;i++)
    {
     if(!color[i])
     {
      if(!dfs(i,1))//随便取一个颜色,因为相邻两次循环就
       {
         flag=1;
         break;
       }
     }

    }
    if(flag) puts("No");
    else puts("Yes");

}

五、匈牙利算法(两组结点最多的匹配)

首先按照第一选择进行匹配,后面匹配冲突的时候,去看先匹配的那个可不可以调整。

使用bool数组st保证回去调整的时候不会选到同一个点,也就是一个点不会被同一个点匹配到两次。

#include<bits/stdc++.h>
//861二分图的最大匹配(匈牙利算法)
using namespace std;
const int N=500,M=100010;
int e[N],ne[M],h[N],idx;
int st[N];
int match[N],n1,n2,m;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int find(int u)
{

    for(int i=h[u];i!=-1;i=ne[i])//与u相连的所有点
    {
        int j=e[i];
        //因为可能在调整的过程中重复调用find函数,此时st[j]已经为true
        //不会再选这个点了
        if(!st[j])//之前有没有被考虑过
        {
            st[j]=true;
            //如果与其相连的点没有匹配
            //或者匹配了但是可以更换
            if(match[j]==0||find(match[j]))
            {
                //匹配上一个点
                match[j]=u;
                return true;
            }

        }
    }
    //尝试了所有的出边所连的点都不行的时候
    return false;
}
int main()
{
  cin>>n1>>n2>>m;
  while(m--)
  {
      int a,b;
      cin>>a>>b;
      add(a,b);
  }
  int res=0;
  for(int i=1;i<=n1;i++)
  {
      if(find(1))res++;
  }
  cout<<res<<endl;
}


http://www.niftyadmin.cn/n/5372861.html

相关文章

Open CASCADE学习|扫掠

目录 1、BRepPrimAPI_MakePrism Draw Test Harness&#xff1a; C&#xff1a; 2、BRepPrimAPI_MakeRevol Draw Test Harness&#xff1a; C&#xff1a; 3、BRepOffsetAPI_MakePipeShell Draw Test Harness&#xff1a; C&#xff1a; Draw Test Harness&#xff1a;…

【MySQL】数据库的基础——数据库的介绍、MySQL的介绍和架构、SQL分类、MySQL的基本使用、MySQL的存储引擎

文章目录 MySQL1. 数据库的介绍1.2 主流数据库 2. MySQL的介绍2.1 MySQL架构2.2 SQL分类2.3 MySQL的基本使用2.4 MySQL存储引擎 MySQL 1. 数据库的介绍 数据库&#xff08;Database&#xff0c;简称DB&#xff09;是按照数据结构来组织、存储和管理数据的仓库。它是长期存储在计…

python+django学习交流论坛系统244t6

系统可以提供信息显示和相应服务&#xff0c;其管理员管理用户发布的博客文章以及用户之间的论坛交流信息&#xff0c;管理留言以及文章分类信息。用户在论坛交流模块发布帖子以及评论帖子&#xff0c;在前台查看和评论其他用户发布的博客文章&#xff0c;收藏博客文章&#xf…

Netty应用(四) 之 Reactor模型 零拷贝

目录 6.Reactor模型 6.1 单线程Reactor 6.2 主从多线程Reactor (主--->Boss | 从--->Worker | 一主多从机制) 7.扩展与补充 8.Reactor模型的实现 8.1 多线程Reactor模型的实现&#xff08;一个Boss线程&#xff0c;一个Worker线程&#xff09; 8.2 多线程Reactor模…

python+vue+django体育场地器材预约管理系统dyn9h

技术栈 后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django Python版本&#xff1a;python3.7 数据库&#xff1a;mysql5.7 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm .体育馆管理系统有管理员和用户两个角色。用户功能有场地…

常见性能优化策略

对于经常接触高并发服务的同学来学&#xff0c;会经常涉及到性能优化&#xff0c;但是由于平时很少总结&#xff0c;内容会比较分散&#xff0c;这里简单做一些总结 1&#xff1a;空间换时间 比如一些数据的访问需要很快返回结果&#xff0c;原本在磁盘上的数据&#xff0c;需…

电商小程序04实现登录逻辑

目录 1 创建自定义方法2 获取用户名和密码3 验证用户是否同意协议4 验证用户名和密码总结 上一篇我们实现了登录功能的前端界面&#xff0c;这一篇实现一下登录的具体逻辑。 1 创建自定义方法 一般如果页面点击按钮需要有事件响应的&#xff0c;我们用自定义方法来实现。打开我…

43.1k star, 免费开源的 markdown 编辑器

简介 项目名&#xff1a; MarkText-- 简单而优雅的开源 Markdown 编辑器 Github 开源地址&#xff1a; https://github.com/marktext/marktext 官网&#xff1a; https://www.marktext.cc/ 支持平台&#xff1a; Linux, macOS 以及 Windows。 操作界面&#xff1a; 在操作界…