搜索与图论(三)

一、最小生成树

1.1Prim算法

朴素版Prim

一般用于稠密图

算法流程:

集合表示当前已经在连通块的点

1.初始化距离,把所有距离都初始化为正无穷

2.n次迭代,找到集合外距离最小的点 ->t

3.用t来更新其它点到集合的距离

cpp 复制代码
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 510,INF = 0x3f3f3f3f;

int n,m;
int g[N][N];
int dist[N];
bool st[N];

int prim()
{
    memset(dsit,0x3f,sizeof dsit);
    
    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;
        }
        
        if(i && dist[t] == INF) return INF;
        
        for(int j = 1;j <=n;j ++) dist[j] = min(dist[j],g[t][j]);
        st[t] = true;
    }
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    
    memset(g,0x3f,sizeof g);
    
    while(m --)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        g[a][b] = g[b][a] = min(g[a][b],c);
    }
    
    int t = prim();
    
    if(t == INF) puts("impossible");
    else printf("%d\n",t);
    
    return 0;
}

1.2Kruskal算法

一般用于稀疏图

算法流程:

1.将所有边按照权重从小到大排序

2.枚举每一条边(a,b),权重为c

如果(a,b)不连通,则将这条边加入集合中

cpp 复制代码
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 100010;

int n,m;
//并查集的集合
int p[N];

struct Edge
{
    int a,b,w;

    bool operator < (const Edge &W)const
    {
        return w < W.w;
    }
}edges[N];

int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}
int main()
{
    scanf("%d%d",&n,&m);

    for(int i = 0;i < m;i ++)
    {
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        edges[i] = {a,b,w};
    }

    sort(edges,edges + m);

    for(int i = 1;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,w = edges[i].w;

        //知道a与b的祖宗节点
        a = find(a),b = find(b);

        //判断a与b是否连通
        if(a != b)
        {
            //集合合并
            p[a] = b;
            res += w;
            cnt ++;
        }
    }

    if (cnt < n - 1) puts("impossible");
    else printf("%d\n",res);

    return 0;
}

二、二分图

二分图当且仅当图中不含奇数环

2.1染色法

cpp 复制代码
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 100010,M = 200010;

int n,m;
int h[N],e[M],ne[M],idx;
int color[N];

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}

bool dfs(int u,int c)
{
    //当前点的颜色是c
    color[u] = c;

    for(int i = h[u];i != -1;i = ne[i])
    {
        int j = e[i];
        if(!color[j])
        {
            if(!dfs(j,3 - c)) return false;
        }
        else if (color[j] == c) return false;
    }
    return true;
}

int main()
{
    scanf("%d%d",&n,&m);

    memset(h,-1,sizeof h);

    while(m --)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }

    bool flag = true;
    for(int i = 1;i <=n;i ++)
    {
        if(!color[i])
        {
            if(!dfs(i,1))
            {
                flag = false;
                break;
            }
        }
    }

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

    return 0;
}

2.2匈牙利算法

cpp 复制代码
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 510,M = 100010;

int n1,n2,m;
int h[N],e[M],ne[M],idx;
int match[N];
bool st[N];

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
bool find(int x)
{
    for(int i = h[x];i != -1;i = ne[i])
    {
        int j = e[i];
        if(!st[j])
        {
            st[j] = true;
            if(match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d%d%d",&n1,&n2,&m);

    memset(h,-1,sizeof h);

    while(m --)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }

    int res = 0;
    for(int i = 0;i <= n1;i ++)
    {
        memset(st,false,sizeof st);

        if(find(i)) res ++;
    }
    printf("%d\n",res);

    return 0;
}
相关推荐
cpp_25011 小时前
P10570 [JRKSJ R8] 网球
数据结构·c++·算法·题解
cpp_25011 小时前
P8377 [PFOI Round1] 暴龙的火锅
数据结构·c++·算法·题解·洛谷
uesowys1 小时前
Apache Spark算法开发指导-Factorization machines classifier
人工智能·算法
季明洵1 小时前
C语言实现单链表
c语言·开发语言·数据结构·算法·链表
shandianchengzi2 小时前
【小白向】错位排列|图文解释公考常见题目错位排列的递推式Dn=(n-1)(Dn-2+Dn-1)推导方式
笔记·算法·公考·递推·排列·考公
I_LPL2 小时前
day26 代码随想录算法训练营 回溯专题5
算法·回溯·hot100·求职面试·n皇后·解数独
Yeats_Liao2 小时前
评估体系构建:基于自动化指标与人工打分的双重验证
运维·人工智能·深度学习·算法·机器学习·自动化
cpp_25012 小时前
P9586 「MXOI Round 2」游戏
数据结构·c++·算法·题解·洛谷
浅念-2 小时前
C语言编译与链接全流程:从源码到可执行程序的幕后之旅
c语言·开发语言·数据结构·经验分享·笔记·学习·算法
有时间要学习2 小时前
面试150——第五周
算法·深度优先