首页 > 编程语言 >算法学习笔记-----图论基础

算法学习笔记-----图论基础

时间:2024-08-17 14:52:17浏览次数:11  
标签:图论 int -- cin push 算法 maxn ind -----

基础知识

两种存储方式:邻接矩阵、邻接表。
两种遍历:dfs,bfs。
图的遍历
考虑深搜,发现出现环的情况进行不下去。
一种可行的方案是反向建边后从最后一个点往后开始 dfs 或 bfs。

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;

const int maxn = 1e5+3;
vector<int> p[maxn];
int a[maxn];

void dfs(int x,int v)
{
    a[x]=v;
    for(int i=0;i<p[x].size();i++)
    {
        if(!a[p[x][i]])
        dfs(p[x][i],v);
    }
}

void solve()
{
    int n,m; cin>>n>>m;
    int u,v;
    for(int i=1;i<=m;i++) // 反向建边
    {
        cin>>u>>v;
        p[v].push_back(u);
    }
    for(int i=n;i>=1;i--)
    {
        if(!a[i])
        {
            dfs(i,i);
        }
    }
    for(int i=1;i<=n;i++)
    cout<<a[i]<<" ";
    return ; 
}

int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T; T=1;
    while(T--) solve();
    return 0;
}
DAG 与 拓扑排序

DAG:有向无环图。
拓扑排序:每次选入度为 0 的点,删除它和它的出边。
在这里插入图片描述
拓扑排序的结果不唯一,例如在上图中,a-e-b-c-d 或 a-b-e-c-d 或 a-b-c-e-d 都是正确的答案。
拓扑排序只能在 DAG 上进行,有向才能确定删除的顺序,无环才能保证排序过程正确进行,如果有环的话会导致排序到某一步出现没有入度为 0 的点。
同理,如果拓扑排序进行不下去了,说明这个图里有环。

最大食物链计数
求食物链的总数,必须从生产者开始,到最高级消费者结束,模拟拓扑排序的过程即可。

#include<bits/stdc++.h>
#define endl '\n'
#define int long long

using namespace std;

const int mod = 80112002;
const int maxn = 5e3+3;
int outd[maxn],ind[maxn];
int f[maxn]; // 记录以 i 为终点的方案数
vector<int>p[maxn];
queue<int>q;

void solve()
{
    int n,m;
    cin>>n>>m;
    int u,v;
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        p[u].push_back(v);
        outd[u]++;
        ind[v]++;
    }
    for(int i=1;i<=n;i++)
    {
        if(!ind[i]) // 将入度为 0 的点加入队列 
        {
            q.push(i);
            f[i]=1; // 初始时,以入度为 0 的点作为子食物链的数量为 1 
        }         
    }
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<p[x].size();i++)
        {
            int y=p[x][i];
            f[y]=(f[x]+f[y])%mod;
            ind[y]--;
            if(!ind[y]) q.push(y);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(!outd[i])
        ans=(ans+f[i])%mod;
    }
    cout<<ans<<endl;
    return ;
}

signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T; T=1;
    while(T--) solve();
    return 0;
}

最长路
除了 1 之外可能还有入度为 0 的点,因此要在跑拓扑排序前先把这些点对结果的影响消除。注意到边权可能为负数,因此初始化存最长路的数组时注意不要初始化为 0。

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;

const int maxn = 1e5+3;
struct edge
{
    int to,len;
};
vector<edge>p[maxn]; // 存边和边权
int f[maxn],ind[maxn]; // 存最长路和入度
queue<int>q;

void solve()
{
    int n,m; 
    cin>>n>>m;
    int u,v,w;
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v>>w;
        p[u].push_back({v,w});
        ind[v]++;
    }
    for(int i=2;i<=n;i++)
    {
        f[i]=-1e9;
        if(!ind[i]) q.push(i);
    }
    // 将除 1 外入度为 0 的点的影响消除 
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<p[x].size();i++)
        {
            ind[p[x][i].to]--;
            if(!ind[p[x][i].to]) q.push(p[x][i].to);
        }
    }
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<p[x].size();i++)
        {
            f[p[x][i].to]=max(f[p[x][i].to],f[x]+p[x][i].len);
            ind[p[x][i].to]--;
            if(!ind[p[x][i].to]) q.push(p[x][i].to);
        }
    }
    if(f[n]==-1e9) cout<<-1<<endl;
    else cout<<f[n]<<endl;
    return ;
}


int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T; T=1;
    while(T--) solve();
    return 0;
}

车站分级
由于每次停靠都是按顺序来的,因此每段停靠区间里没有出现过的车站一定比出现过的等级要低,依据此进行建图,用等级低的车站指向等级高的车站,然后拓扑排序每次删去所有入度为0的点,最后看拓扑排序由多少层即可。

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;

const int maxn = 1e3+5;
bool pd[maxn]; // 记录每组数据的车站停靠情况
int a[maxn];
int p[maxn][maxn];
int in[maxn]; // 记录每个节点的入度
int ans;

void solve()
{
    int n,m;
    cin>>n>>m;
    while(m--)
    {
        memset(pd,0,sizeof(pd));
        int s; cin>>s;
        for(int i=1;i<=s;i++)
        {
            cin>>a[i];
            pd[a[i]]=true;
        }
        for(int i=a[1];i<=a[s];i++)
        {
            if(!pd[i])
            {
                for(int j=1;j<=s;j++)
                {
                    if(!p[i][a[j]])
                    {
                        p[i][a[j]]=1;
                        in[a[j]]++;
                    }
                }
            }
        }  
    }
    queue<int> q;
    // 将入度为 0 的点加入队列
    for(int i=1;i<=n;i++)
    {
        if(!in[i]) q.push(i);
    }
    // 拓扑排序 一次处理一层
    while(!q.empty())
    {
        int size=q.size();
        ans++;
        for(int i=0;i<size;i++)
        {
            int x=q.front();
            q.pop();
            for(int j=1;j<=n;j++)
            {
                if(p[x][j])
                {
                    in[j]--;
                    p[x][j]=0;
                    if(!in[j]) q.push(j);
                }
            }
        }
    }
    cout<<ans<<endl;
    return ;
}

int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T; T=1;
    while(T--) solve();
    return 0;
}

标签:图论,int,--,cin,push,算法,maxn,ind,-----
From: https://blog.csdn.net/jinxdtaiy/article/details/141200011

相关文章

  • 括号生成-力扣
    classSolution{private:vector<string>result;stringstr;public:voidbacktracking(intn,intl,intr){if(l==n&&r==n){result.push_back(str);return;}if(l<n){......
  • 合并K个升序链表-力扣
    /***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode():val(0),next(nullptr){}*ListNode(intx):val(x),next(nullptr){}*ListNode(intx,ListNode*next):val(x),next(ne......
  • Hexo-Github Actions 自动部署方案
    前阵子因为很久没有捡起来写博客,导致电脑的node环境各种版本问题,本地压根运行不起来,所以折腾了一下Hugo方案,感觉Hugo相较于Hexo还是有很多优势的,让我印象比较深的是:整个环境较为独立,不再像Hexo需要依赖电脑Node版本,各种插件需要独立版本,随着Hexo或者Node版本升......
  • Hexo-常用插件&配置
    参考文档地址:Plugins,Hexo官方插件列表地址theme-next/awesome-next::sunglasses:ThemeNexT,AWESOMENexT!这里汇总一下自己比较常用的插件以及相关的配置,希望对你有所帮助。注意:我使用的是next主题,很多配置可能是主题专用!RSS安装hexo-generator-feed插件即可n......
  • 代码随想录算法训练营day09|151.翻转字符串里的单词,卡码网:55.右旋转字符串,28.实现 str
    151.翻转字符串里的单词题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/description/暴力removeExtraSpaces:voidremoveExtraSpaces(string&s){for(inti=s.size()-1;i>0;i--){if(s[i]==''&&s[i]=......
  • 最好用的Linux发行版---WSL
    使用debian开发半年,那个号称稳定的操作系统,ubuntu也是基于它的testing版本开发的,在一次设置testing更新后英伟达驱动掉了、引导区无法启动、bios损坏,现在老实了,换回了Window,并且激进的选择了win11,但我还是难以忘记linux爽快的开发体验,便用上了wsl安装Linux控制面板->程......
  • Langchain pandas agent - Azure OpenAI account
    Langchainpandasagent结合AzureOpenAI账户使用时,主要涉及到通过AzureOpenAI提供的自然语言处理能力,来操作pandasDataFrame或进行相关的数据处理任务。以下是关于这一结合使用的详细解析:一、Langchainpandasagent概述在LangChain中,Agent是一个核心概念,它代表了......
  • Redis5多实例安装-Redis
    本文是按照Redis5二进制安装的后续1、创建6380、6381目录,分别将安装目录下的redis.conf拷贝到这两个目录下cd/usr/local/redis6/bin/mkdirredis6380mkdirredis6381cpredis.confredis6380/cpredis.confredis6381/2、修改配置文件redis6380viredis6380/redis.con......
  • 贪心-多机调度问题
    多机调度问题分析问题描述在多机调度问题中,我们有n个独立的作业和m个相同的机器。每个作业i需要处理时间ti。我们的目标是找到一个调度方案,使得所有作业尽可能快地完成。贪心策略最长处理时间优先:优先分配处理时间最长的作业到最先可用的机器上。情况分类A:n......
  • C语言-写一个用矩形法求定积分的通用函数,分别求积分区间为[0,1]sinx,cosx,e的x方的定积
    一、题目要求:二、思路①数学方面:矩形法求定积分的公式将积分图形划分成为指定数量的矩形,求取各个矩形的面积,然后最终进行累加得到结果1.积分区间:[num1,num2]2.分割数量:count每个矩形的边长:dx=(num2-num1)/count3.被积分函数:f(x)(f-对应不同的被积分函数sin......