首页 > 其他分享 >图论一

图论一

时间:2023-08-08 23:55:28浏览次数:23  
标签:输出 图论 idx int ne add include

图论(1)

图的存储

直接存边

int e[N];
e[1]=3;//1->3有条边

邻接表

int h[N],e[N],ne[N],idx;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx,idx++;
}
void init(){
    meset(h,-1,size of(h));//所有头结点为空
}

也可以用vector e[N];

图的遍历

树和图的深度优先搜索

void dfs(int u){
    st[u]=true;
    
    for(int i=h[u];i!=-1;i=ne[i])//遍历出边
    {
        int j=e[i];
        if(!st[j]) dfs(j);
    }
}

846 树的重心
有n个结点,n-1条边
求删除重心剩余各连通块中数的最大值
重心:删除树中一个结点,剩余的各个连通块的数的最大值最小,这个点就是重心
输入描述

  1. 结点数n($1\le n\le 10^5$);
  2. n-1行 a b表示一条边

输出格式
输出一个整数m,表示结果
样例
输入样例

9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6

输出样例

4

算法思路
删去每个结点,然后存储最大连通图,然后在储存的连通图里选一个最小的。
深度优先遍历可以求得子树的大小

# 1
## 2
- 8
- 5
## 4
- 3
    - 9
- 6
## 7

算法代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int N=100010,M=N*2;
int n,m;
int h[N],e[M],ne[M],idx;
bool st[N];//go
int ans=N;//init max

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

//以u为根的树中的结点数量,返回的并不是我们要的而是过程中要的
int dfs(int u){
    st[u]=true;
    
    int sum=1,res=0;//sum存储子树数量,res存储每次删点的连通块最大值
    
    for(int i=h[u];i!=-1;i=ne[i])//读入u边指向的边,只要不为空就继续读
    {
       int j=e[i]; 
       if(!st[j]){
           int s=dfs(j);
           res=max(res,s);
           sum+=s;
       }
    }
    res=max(res,n-sum);
    ans=min(ans,res);
    return sum;
}
int main(){
    cin>>n;
    memset(h,-1,sizeof(h));
    
    for(int i=0;i<n-1;i++){
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

BFS

while(queue不空){
    t<-队头;
    拓展t所有相邻的点x
    if(x未遍历){
        queue<-x;
        d[x]=d[t]+1;
    }
}

846图中点的层次 题目描述
n个点,m条边,可能有重边和自环
边长度都是1,点的编号1-n;
请你求出1到n号点的最短距离,如果不能到输出-1;
输入格式

  1. n,m($1\le n,m\le 10^5$)
  2. m行a,b边
    输出格式
    输出1到n的最短距离
    输入样例
4 5
1 2
2 3
3 4
1 3
1 4

输出样例

1

code

#include <iostream>
#include <cstring>
using namespace std;
const int N=100010;
int n,m;
int d[N],q[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int bfs(){
    int hh=0,tt=0;
    q[0]=1;//1号点入队
    
    memset(d,-1,sizeof(d));//init d
    
    d[1]=0;
    while(hh<=tt){
        int t=q[hh++];//队列指针出队
        
        for(int i=h[t];i!=-1;i=ne[i]){//i指向j的指针
            int j=e[i];//点
            if(d[j]==-1){
                d[j]=d[t]+1;//t是上一个点
                q[++tt]=j;
            }
        }
    }
    if(d[n] == -1) return -1;
    return d[n];
}
int main(){
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    cout<<bfs()<<endl;
    return 0;
}

有向图的拓扑序列

拓扑队列:所有的边都是从前指向后;
必须是有向无环图才可能有拓扑序(DAG);
有向无环图也叫拓扑图

queue <-所有入度为0的点
while(queue不空){
    t<-队头;
    枚举t所有出边t到j;
    删掉t->j;//d[j]--入度;
    if(d[j]==0)    queue<-j;
}

一个有向无环图一定至少存在一个入度为零的点
有向图的拓扑序列
n点m边,点的编号1-n可能有重边和自环
对于图中的每条边 (x,y) ,x 在 A中都出现在 y 之前,则称 A 是该图的一个拓扑序列。
请输出拓扑序列,不存在输出-1;
输入格式

  1. n点m边;($1\le n,m\le 10^5$)
  2. m行x,y边

输出格式
存在拓扑排序,输出合法的拓扑排序;
不存在输出-1;
输入样例

3 3
1 2
2 3
1 3

输出样例

1 2 3

code

#include <iostream>
#include <cstring>

using namespace std;
const int N=100010;
int n,m;
int h[N],e[N],ne[N],idx;
int q[N],d[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool topsort(){
    int hh=0,tt=-1;
    
    for(int i=1;i<=n;i++){
        if(d[i]==0)
            q[++tt]=i;
    }
    
    while(hh<=tt){
        int t=q[hh++];
        
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(--d[j]==0)
                q[++tt]=j;
        }
    }
    return tt==n-1;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    
    for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        d[b]++;
    }
    if(topsort()==false) cout<<-1<<" ";
    else for(int i=0;i<n;i++) cout<<q[i]<<" ";
    return 0;
}

标签:输出,图论,idx,int,ne,add,include
From: https://www.cnblogs.com/aihaotian/p/17615734.html

相关文章

  • Codeforces 1857D:Strong Vertices 与图论无关的出度最大统计
    1857D.StrongVerticesDescription:给定两个长度均为\(n\)的数组\(a\)和\(b\)(编号\(1\)~\(n\)),如果\(a_u-a_v\geqb_u-b_v\)\((u\neqv)\),那么从\(u\)到\(v\)建立一条有向边。"Strong"定义为:一个点\(V\)可以经过有向图中合法的通路到达其他所有的点。请求解出"......
  • 图论学习笔记
    图图论绘图在线图是由若干给定的顶点及连接两顶点的边所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系。顶点用于代表事物,连接两顶点的边则用于表示两个事物间具有这种关系!点一般用字母v表示,如v1,v2,v3,v4一些简单的术语:路径:一些边组成的序列,满足第一条边的终点......
  • 图论强联通分量(tarjan)算法
    图论强联通分量(tarjan)算法#include<bits/stdc++.h>usingnamespacestd;intn,m,cnt,cntb,ans;vector<int>edge[101];vector<int>belong[101];boolinstack[101];intdfn[101];intlow[101];stack<int>s;voidTarjan(intu){ ++cnt; dfn[u]=......
  • 【笔记】图论:网络流和二分图
    网络流的求法https://www.cnblogs.com/caijianhong/p/16863491.htmlmisc复杂度分析Dinic的复杂度上界为\(O(n^2m)\)。但是特殊情况下会更快,如二分图匹配是\(O(m\sqrtn)\)的;确定流量上限\(f\)时,复杂度为\(O(mf)\)。最小费用最大流的复杂度上界为\(O(nmf)\)。......
  • 图论提高
    复健\(Day7\)图论一\(DGA:\)有向无环图 \(SCC:\)强连通 \(BCC:\)双连通强联通:有向图中,两个顶点至少存在一条路径(两个顶点可以互相到达)强连通图:每两个顶点都强连通的有向图强连通分量:有向图的极大强连通子图\(1.\)有向图的强连通分量问题模型:对于一些存在依赖关系的模型,若......
  • 8.2 day9图论+dp
    100+70+70+20=260感觉如果时间够感觉还能写一下,结果T3超大数据结构写死了T1观察到最短路径仍然最优,直接dij即可,注意判断终点不用等红灯T2暴力是\(O(n^4)\)的,是dp,但是我写的是分层图,同样时间,还没有优化空间,寄设计\(dp_{i,j}\)为跳到\((i,j)\)所需最小花费每次从所有点转移,算......
  • 成都集训图论篇
    [NOI]网格题目描述跳蚤国王和蛐蛐国王在玩一个游戏。他们在一个\(n\)行$m$列的网格上排兵布阵。其中的\(c\)个格子中,每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。我们称占据的格子有公共边的两只跳蚤是相邻的。我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻......
  • 济南 Day 5 图论
    SolutionT1emoairx的二叉树原题链接4114:emoairx的二叉树简要思路一道简单的递归签到题,每次找到较大的数进行除以\(2\),每次递归把步数加一,直到两个点走到同一个点上。完整代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intm;intans(intx......
  • 图论2021版
    图基本概念图可以理解成一个二元组,是由点集V和边集E组成的。G=(V,E),V表示点的集合,E表示边的集合。每条边是一幅点对(v,w)v,w都是点集V中的点。(v,w∈V)图的分类:可以按照边有无方向,可以分为有向图和无向图。比如上图1中,边AB之间没有画出方向(即点之间是无序的),这就是无向图。......
  • 图论入门题
    图论简介:图(Graph)图可以被表示为G={V,E},其中V={v1,...,vN}表示n个点,E={e1,...,eM}表示m条边。常用的储存方式包括邻接表和邻接矩阵。连通分量(ConnectedComponent):各节点间至少存在一条边可以连通。最短路算法:Dijkstra算法是一种求单源最短路的算法,即从一个点开始到......