图论

7 、 图论―连通性

匿名 (未验证) 提交于 2019-12-02 23:52:01
7.1 无向图关键点(dfs 邻接阵) //无向图的关键点,dfs 邻接阵形式,O(n^2) //返回关键点个数,key[]返回点集 //传入图的大小 n 和邻接阵 mat,不相邻点边权 0 #define MAXN 110 void search(int n,int mat[][MAXN],int* dfn,int* low,int now,int& ret,int* key,int& cnt,int root,int& rd,int* bb){ int i; dfn[now]=low[now]=++cnt; for (i=0;i<n;i++) if (mat[now][i]){ if (!dfn[i]){ search(n,mat,dfn,low,i,ret,key,cnt,root,rd,bb); if (low[i]<low[now]) low[now]=low[i]; if (low[i]>=dfn[now]){ if (now!=root&&!bb[now]) key[ret++]=now,bb[now]=1; else if(now==root) rd++; } } else if (dfn[i]<low[now]) low[now]=dfn[i]; } } int key_vertex(int n,int mat[][MAXN],int* key){ int ret

[转]图论-链式向前星

匿名 (未验证) 提交于 2019-12-02 23:49:02
转自: https://blog.csdn.net/hz18790581821/article/details/70233495 我们首先来看一下什么是前向星. 前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序, 并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了. 用len[i]来记录所有以i为起点的边在数组中的存储长度. 用head[i]记录以i为边集在数组中的第一个存储位置. 那么对于下图: 1 2 2 3 3 4 1 3 4 1 1 5 4 5 那么排完序后就得到: 得到: 但是利用前向星会有排序操作,如果用快排时间至少为O(nlog(n)) 如果用链式前向星,就可以避免排序. 1 struct Edge 2 { 3 int next; 4 int to; 5 int w; 6 }; 另外还有一个数组head[],它是用来表示以i为起点的第一条边存储的位置,实际上你会发现这里的第一条边存储的位置其实 在以i为起点的所有边的最后输入的那个编号. head[]数组一般初始化为-1,对于加边的add函数是这样的: 1 void add(int u,int v,int w) //链式前向星存图 2 { 3 Node[cnt].v=v; 4 Node[cnt].w=w; 5 Node[cnt]

图论――因子分解

匿名 (未验证) 提交于 2019-12-02 23:36:01
因子分解相关概念 1、因子分解是图分解的一种方法 2、图G的因子 G i G_i G i ,指至少包含G的一条边的生成子图 (生成子图:包含原图所有顶点,边不管,若边数为m,则不同的生成子图有 2 m 2^m 2 m 个,不同的生成子图≠不同构) 3、图G的因子分解:指将G分解为若干边不重的因子之并 4、图G的n因子:指G的n度正则因子 5、若图G可以分解为若干n因子之并,称G是可n因子分解的 一、图的一因子分解 \quad 图的一个一因子实际上就是图的一个完美匹配的导出子图。一个图能够作一因子分解,也就是它能够分解为若干边不重的 完美匹配的导出子图之并 。 定理1: K 2 n K_{2n} K 2 n 可一因子分解 推论:每个k(k>0)正则偶图G是一可因子分解的 证明: 证明:因为每个k (k>0)正则偶图G存在完美匹配,设Q是它的一个一因子,则G-Q还是正则偶图,由归纳知,G可作一因子分解。 定理2:具有H圈的3正则图可一因子分解 证明:从三正则图中抽取H圈,显然剩下的边构成G的一个一因子,而H圈是偶圈,可分解为两个一因子。故G可分解为三个一因子。 定理3:若三正则图有割边,则它不能一因子分解 证明:假设G的三个一因子为 G 1 , G 2 , G 3 G_1, G_2, G_3 G 1 , G 2 , G 3 ,假设割边 e ∈ G 1 e\in G_1 e ∈ G 1

图论算法(二)最小生成树

匿名 (未验证) 提交于 2019-12-02 23:05:13
图论算法之最小生成树 最小生成树 定义 一幅加权图的最小生成树(MST)是它的一棵权值(树中所有边的权值之和)最小的生成树。 原理 图的一种切分是将图中所有顶点分为两个非空且不重叠的两个集合。横切边是一条连接两个属于不同集合的顶点的边。(下图中的红边即为横切边) (切分定理):在一幅加权图中,给定任意的切分,它的横切边中的权重最小者必然属于图中的最小生成树。 由此可知我们只需要使用切分定理找到最小生成树的一条边,不断重复直到找到最小生成树的所有边。 数据类型基本实现 带权重的边的数据类型 package chapter4; /** * 带权重的边的数据类型 */ public class Edge implements Comparable<Edge> { private final int v;//顶点之一 private final int w;//另外一个顶点 private final double weight;//边的权重 Edge(int v, int w, double weight){ this.v=v; this.w=w; this.weight=weight; } public double weight(){ return weight; } /** 查询边的一个顶点 **/ public int either(){ return v; } /**

【习题讲解】 图论类习题

匿名 (未验证) 提交于 2019-12-02 22:56:40
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/83817767 文章目录 重量不同的硬币 超级牛游戏 damage 重量不同的硬币 题目描述 Fj有N个硬币,编号为1…N。 现在有W个推断,为(A,B),表示硬币A比硬币B重。 寻找并输出一个硬币编号,要求其重量明确不同于其他硬币的个数最多。 如果有多个答案,输出字典序最小的一个。 如果给出的数据有矛盾,输出"IMPOSSIBLE" 输入格式 Line 1: 两个整数: N and W. Lines 2…W+1: 每行两个整数: A, B 输出格式 Line 1: 重量不同于其他硬币的个数最多的硬币编号。 样例数据 input 7 6 1 6 1 5 3 6 4 3 2 4 2 5 output 2 首先,我们知道,如果重量的关系出现了矛盾,一定出现了环,我们可以选择用拓扑排序进行判环: 拓扑排序中的点,要想进入拓扑序列,入度必然为0;但是有环,入度必然不为0.因此,我们统计拓扑排序有多少个点进入拓扑序列,如果有点数sum<n,那么就输出Inpossible。 对于统计大小,我们进行dfs遍历,用cnt[]表示连向这个点的关系,注意每一次的初始化要为1,否则无法进行大小统计。再在反图上做一遍DFS即可。 # include

图论训练之十六

孤者浪人 提交于 2019-12-02 22:29:05
https://www.luogu.org/problem/P4180 不会做...... 严格次小生成树 怎样才能满足 严格次小 ? 考虑 先跑一次最小生成树 在未被选择的边中替换最小生成树中选中的边 如 (u,v,d)这条边 未在最小生成树中 连上这条边后, (u,v) 之间所有的树上的边 都可删去 那么用它替换掉 u和v 之间的 最大边 所以维护一个 (u,v)之间的最大值 又因为 不能相等 所以 再维护一个次大值 很明显,维护树上两点----- 倍增 code : #include<bits/stdc++.h> #define N 400010 #define M 900010 #define INF 2147483647000000 #define ll long long using namespace std; struct edge{ ll u,v,d; ll next; }G[N<<1]; ll tot,head[N],n,m; inline void addedge(ll u,ll v,ll d) { G[++tot].u=u,G[tot].v=v,G[tot].d=d,G[tot].next=head[u],head[u]=tot; G[++tot].u=v,G[tot].v=u,G[tot].d=d,G[tot].next=head[v],head[v]

CSP-S 2019图论总结

三世轮回 提交于 2019-12-02 21:06:46
CSP-S 2019图论总结 一、最短路问题 模板 Floyd算法 void floyd() { memset(map,0x3f,sizeof(map)); for(int i=1;i<=n;i++) map[i][i]=0; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) map[i][j]=min(map[i][j],map[i][k]+map[k][j]); } Dijkstra算法 const int INF=1e9; void dijkstra(int s) { int temp,k,y; memset(dist,0x3f,sizeof(dist)); memset(v,0,sizeof(v)); dist[s]=0; for(int i=1;i<=n;i++) { temp=INF; for(int j=1;j<=n;j++) if(dist[j]<temp && !v[j]) k=j,temp=dist[j]; v[k]=1; for(int j=head[i];j;j=nxt[j]) { y=to[i]; if(dist[y]>dist[k]+val[j]) dist[y]=dist[k]+val[j]; } } } SPFA算法 void spfa(int s) { memset

图论训练之十四

随声附和 提交于 2019-12-02 19:44:07
复习一下网络流二分图 https://www.luogu.org/problem/P3386 分析: 没什么好分析的....... 因为 没学过匈牙利算法,所以就打一个网络流 建一个超级源点和一个超级汇点 此时最大匹配=最大流 code by wzxbeliever: #include<bits/stdc++.h> #define ll long long #define il inline #define ri register int #define lowbit(x) x&(-x) using namespace std; const int maxn=2005; const int maxm=1002005; const int inf=0x7fffffff; struct node{ int to,next,w; }edg[maxm<<1]; int cnt,n,m,S,T,x,y,k; int dp[maxn],head[maxn]; queue<int>Q; il void add(int u,int v,int w){ cnt++; edg[cnt].next=head[u]; edg[cnt].to=v; edg[cnt].w=w; head[u]=cnt; } il bool bfs(){ while(!Q.empty())Q.pop(); memset(dp

图论笔记

随声附和 提交于 2019-12-02 19:12:07
(及其详尽的大佬介绍%%%) https://zybuluo.com/juruo/note/1535384#2dfs小规模万能暴力算法 来源: https://www.cnblogs.com/phemiku/p/11759712.html

【图论】DAG上的dp:Codeforces 721C Journey

て烟熏妆下的殇ゞ 提交于 2019-12-02 19:07:08
DAG上的dp:Codeforces 721C Journey 题目描述 https://codeforces.com/problemset/problem/721/C Irina来到了城市Berlatov。该城市中有n个景点,编号从1至n,其中一些景点被单向道路连接。图中没有环路。最初Irina站在景点1,她的旅行终点是景点n。Irina想要游玩尽可能多的景点,但是,Irina在这座城市中的停留时间是有限的,她不能在这里呆超过T时间。帮助Irina规划在不超过T时间内,她可以游玩多少个景点。保证在T时间内至少有一条路径可以从景点1到达景点n。 Input 第一行:n,m,T——景点数量,道路的数量,游玩时间限制(2 ≤ n ≤ 5000,  1 ≤ m ≤ 5000,  1 ≤ T ≤ 109) 下面m行,每行u,v,t从u到v有一条路,且该条道路需要花费t时间通过。保证道路不会形成回路。数据保证有解。 Output 第一行输出数字k(2 ≤ k ≤ n)——Irina最多可游玩的景点 第二行按游玩顺序输出k个不同的景点的编号 如果有多种方案,输出其中一种 Examples input 4 3 13 1 2 5 2 3 7 2 4 8 output 3 1 2 4 input 6 6 7 1 2 2 1 3 3 3 6 3 2 4 2 4 6 2 6 5 1 output 4 1