第三十六天:其实它们都是“图”

本文介绍了图的基本概念,包括无向图和有向图,以及图的两种存储方式——邻接矩阵和邻接表。重点讲解了二分图的判定算法,通过深度优先搜索实现,确保相邻顶点颜色不同。此外,还探讨了图着色问题,提供了一个完整的二分图染色问题解决方案。这些图论思想在数学建模、物流管理等领域有着广泛应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天我们来聊一聊图。(开始爆更)

图是什么?

图是由顶点(vertex、node)和边(edge)组成。顶点的集合是V,边的集合是E,图记为:G=(V,E)。
图分为无向图和有向图两种,在无向图中两个相连的顶点权值应该是只有一个,对于有向图来说,不同方向的权值是不同的,因此就需要用不同的数据存储他们。

图的存储方式

图有两种存储方式,邻接矩阵和邻接表,两者都有优点和缺点。
1.邻接矩阵:
d[i][j]表示的是从i顶点到j顶点的距离,显然自己到本身的距离为0,在无向图中这是一个对称的矩阵

d[i][j]==d[j][i];
d[i][i]==0;

在有向图中,可能不是对称的矩阵,空间的存储花费O(V^2)的空间,不利于稀疏图的存储。这个时候就需要用到邻接表来存储提高空间的利用率。

同时,当出现重边(两个顶点有两条通向的边)或者自环的时候,这个时候也需要用邻接表来存储,当然邻接表的复杂度也相对较高。
2.邻接表:
知识把仅有的边和顶点保存起来,那么空间复杂度就是O(V+E)
那邻接表的缺点是什么呢?就是比邻接矩阵相对复杂,并且如果想要查询两点间是否有边的时候需要遍历整个链表才可以。

邻接表的存储方式

其实方式很多,我比较喜欢用vector

#include <iostream>
#include <vector>
using namespace std;
const int MAX_N=1e5;

vector<int> G[MAX_N];
int mian()
{
    int V,E;
    cin>>V>>E;
    for (int i = 0; i < E; i++)
    {
        int s,t;
        cin>>s>>t;
        G[s].push_back(t);

    }
    return 0;
}

例题:二分图的判定

给定一个具有n个顶点图,要给每个顶点上色,并且要使得相邻的顶点颜色不同。时否能够最多用两种颜色进行染色,保证没有重边和自环。
1<=n<=1000

图着色问题:

相邻顶点染成不同颜色的问题叫做图着色问题。对图进行染色所需要的最小颜色数称为最小着色数。最小着色数是2的图叫做2分图。

对于这道题来说,一旦从某一个顶点出发,将它染成一种颜色,那么相邻的顶点颜色一定是确定的,如果已经涂成了相同的颜色就直接返回false,如果还没有涂色那么就从这个为涂色再出发,先给它涂上另一种颜色再从该点出发去搜索不停地重复这一过程。

初始化

我们需要保存图

const int M=1e3+3;
vector<int> G[M];

输入是点数和边数

int V,E;

我们还需要判断顶点是否染色,我们不需要再开一个数组判断是否可以染色,一开始初始化成0,代表未染色,染色就变成1.这里有一个小技巧,另一种颜色我们如何表示呢?
其实只有两种颜色嘛,可以用1和-1表示最方便,方便查找。搜索参数第一个应该是顶点的编号,还需要该点的涂的颜色,因此用1和-1这样的表示方法最方便

int color[M];

搜索

bool dfs(int v,int c)
{
    color[v]=c;//未染色直接染成c
    for (int i = 0; i < G[v].size(); i++)
    {
        if(G[v][i] == c) return false;//同色就说明一定不能成功的
        if(G[v][i] == 0 && !dfs(G[v][i],-c)) return false;//没有涂色,就从这个点开始找
    }
    return true;
}

完整实现

#include <iostream>
#include <vector>
using namespace std;
const int M=1e3+3;

vector<int>G[M];
int color[M];

bool dfs(int v,int c)
{
    color[v]=c;
    for (int i = 0; i < G[v].size(); i++)
    {
        if(G[v][i] == c) return false;
        if(G[v][i] == 0 && !dfs(G[v][i],-c)) return false;
    }
    return true;
}
int main()
{
    int V,E;
    cin>>V>>E;
    for (int i = 0; i < E; i++)
    {
        int s,t;
        cin>>s>>t;
        G[s].push_back(t);
    }

    for (int i = 0; i < V; i++)
    {
        if(color[i] == 0)
        {
            if(!dfs(i,1))
            {
                cout<<"No"<<endl;
                return 0;
            }
        }
    }
    cout<<"Yes"<<endl;
    return 0;
}

这道题还是比较简单的,但是图论的思想在各个领域里面都能用到。竞赛方面无论是数学建模还是物流管理,智能车还是无人驾驶,都非常重要。拓扑排序的思想也能在其中体现。
校学生会部长团答辩也答完了,近期有要开始补题了…11月还有7天,哎,还有两篇项目策划书,高数国赛,知识竞赛省赛…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shirandexiaowo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值