图论

图论找环

百般思念 提交于 2019-12-02 10:55:01
竞赛中找环有许多种问题,判断是否有环,找到环上的点,找到环上的边等等。 而只需要找到环上相邻的两点,或者环上的一条边就可以解决这三个问题。 有向图中,可以用拓扑排序的方法,把将拓扑排序完后限制条件仍未被清零的点即在环上的点。 #include <bits/stdc++.h> #define N 1000101 using namespace std; int n, m, cnt, lin[N], deg[N]; struct edg { int to, nex; }e[N]; inline void add(int f, int t) { deg[t]++; e[++cnt].nex = lin[f]; e[cnt].to = t; lin[f] = cnt; } void topu() { queue <int> q; for (int i = 1; i <= n; i++) if (!deg[i]) q.push(i); while (!q.empty()) { int cur = q.front(); q.pop(); for (int i = lin[now]; i; i = e[i].nex) { int to = e[i].to; deg[to]--; if (!deg[to]) q.push(to); } } } int main() { scanf("%d%d",

图论篇1——图的基本概念

对着背影说爱祢 提交于 2019-12-02 07:00:50
图的基本性质 顶点(vertex) 上图中黑色的带数字的点就是顶点,表示某个事物或对象。由于图的术语没有标准化,因此,称顶点为点、节点、结点、端点等都是可以的。叫什么无所谓,理解是什么才是关键。 边(edge) 上图中顶点之间蓝色的线条就是边,表示事物与事物之间的关系。需要注意的是边表示的是顶点之间的逻辑关系,粗细长短都无所谓的。包括上面的顶点也一样,表示逻辑事物或对象,画的时候大小形状都无所谓。 有向/无向图(Directed Graph/ Undirected Graph) 有向图和无向图,两者的区别在于,有向图中的边是有方向性的。(可以把无向图视为“双向”的有向图,构造无向图用的就是这种方法) 一般到底是有向图还是无向图要根据实际情况判断,比如在A、B两点之间的一条路,那一定是个无向图。 权重(weight) 边的权重(或者称为权值、开销、长度等),即每条边都有与之对应的值。例如当顶点代表某些地点时,两个顶点间边的权重可以为两点的距离。 连通图/连通分量(connected graph/connected component) 如果在图G中,任意2个顶点之间都存在路径,那么称G为连通图(注意是任意2顶点)。如果把下图看为两个图,就是两个连通图。 连通分量 也叫最(极)大连通子图,把上图看为一个整体,它不是一个连通图,但它有多个连通子图,0,1,2,3

图论--割边--Tarjan模板

旧巷老猫 提交于 2019-12-02 05:56:36
#include<iostream> #include<stdio.h> #include<vector> using namespace std; const int maxn=100010; int head[maxn],ver[maxn*2],Next[maxn*2]; int dfn[maxn],low[maxn],sta[maxn]; int n,m,tot,num,root; bool cut[maxn]; void add(int x,int y) { ver[++tot]=y; Next[tot]=head[x]; head[x]=tot; } void tarjan(int x) { dfn[x]=low[x]=++num; int flag=0; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { flag++; if(x!=root||flag>1) cut[x]=1; } } else low[x]=min(low[x],dfn[y]); } } int main() { cin>>n>>m; tot=1; for(int i=1;i<=m;i++) { int x,y;

图论训练之十二

大憨熊 提交于 2019-12-02 05:08:20
https://www.luogu.org/problem/P3022 吐槽: 什么 狗屁标签,动态规划?单调队列? 还有就是我为什么 纯dfs的题总是做不到 分析: 这道题有 special judge 说明乱搞能过 结论: 直接在原图的每一个连通块的一颗树上进行树形dp 考虑 u-v这条边 如果与v相连的树边为偶数,则 u-v 这条边保留 如果为奇数,则 u-v 这条边不保留 如果成立的话,则整个图一定是成立的,反之整个图也不成立 至于为什么这么干 找了很多的题解,都没说个东西,然后我想了一晚上一上午也没肝出来 无奈我也就只能这样谢了,见谅 乱搞code: #include<bits/stdc++.h> #define INF 2147483647 #define ll long long int Inp(){ char c = getchar(); int Neg = 1; while(c < '0' || c > '9'){ if(c == '-') Neg = -1; c = getchar(); } int Sum = 0; while(c >= '0' && c <= '9'){ Sum = ((Sum << 3) + (Sum << 1)) + c - '0'; c = getchar(); } return Neg * Sum; } int Head[50010]

[CSP-S模拟测试]:环(图论+期望)

若如初见. 提交于 2019-12-01 23:59:04
题目传送门(内部题79) 输入格式   第一行读入两个整数$n,e$表示节点数及$cwystc$已确定的有向边边数。   接下来$e$行,每行两个整数$x,y$描述$cwystc$确定的边。 输出格式   输出一个整数表示期望陪妹子的天数。 样例 见下发文件 数据范围与提示   对于$30\%$的数据:$n\leqslant 300$   对于另外i$20\%$的数据:$e=0$   对于另外$20\%$的数据:$e=\frac{n\times (n-1)}{2}$   对于$100\%$的数据:$n\leqslant 100,000,e\leqslant 100,000$ 题解 先转化一下题意,即让我们求竞赛图的期望最小环的个数。 而对于一张竞赛图,其要么是一张拓扑图,要么存在一个三元环。 因为该图不存在环,于是问题转化为三元环计数。 考虑容斥,不妨设$p[i]$表示点$i$的出度,那么对于三元组$(i,x,y)\{x\in p[i],y\in p[i],x\neq y\}$不组成三元环,而且这样的三元组只会在第$i$点枚举一次。 不妨再设$q[i]$表示连接点$i$未确定的边数,那么期望要减去: $$\frac{p[i]\times (p[i]-1)}{2}+p[i]\times \frac{q[i]}{2}+\frac{q[i]\times (1-q[i])}{2}

【刷题】【图论】树上最短路

主宰稳场 提交于 2019-12-01 23:56:13
给你n个叶子点互相的最短路长度,构造若干个点的最小生成树 这里引入的: 一个点到树的最短距离 #include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; int n; const int N=33; int g[N][N];//注意我只存了,右上角 int main() { while(~scanf("%d",&n) && n) { for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++) scanf("%d",&g[i][j]); int ans=g[1][2]; for(int i=3;i<=n;i++) { int nw=1<<30; for(int j=1;j<i;j++) for(int k=j+1;k<i;k++) nw=min(nw,g[k][i]+g[j][i]-g[j][k]); ans+=(nw>>1); } printf("%d\n",ans); } return 0; } 来源: https://www.cnblogs.com/xwww666666/p/11722117.html

图论☞广度优先遍历

喜夏-厌秋 提交于 2019-12-01 19:22:16
对于图这种数据结构,一般有两种遍历即深度优先(dfs),和广度优先(bfs),假设我们有如下这张图: 访问过程 现在假设计算0到其它点的路径,根据 广度优先遍历 ,广度优先遍历需要借助于队列这种数据结构,思路分析: 注意:访问某一个顶点时,要进行标记是否被访问过以及其巧妙利用数组的索引跟顶点 计算路径 那如何找到顶点到某一点的路径?其实思路跟深度优先遍历中查找路径方法是一样的,但是在记录访问的数组中保存的数据却是不一样的(代码实现中 from 数组),这就跟我们的遍历方式有关,深度优先遍历采用递归,广度优先遍历是借助于队列这种数据结构。 上述步骤我们可以这样记录(初始化数组的值为-1):arr[6]=0,arr[0]=-1,因此路径是0->6。同时我们也可以发现一个问题,这次我们一下就找到路径。以下是深度优先遍历(path)和广度优先遍历(path2) from 数组内部的数据 代码实现 public class ShortestPath { /**图的引用*/ private Graph G; /**起始点*/ private int s; /**记录bfs的过程中节点是否被访问*/ private boolean[] visited; /**记录路径, from[i]表示查找的路径上i的上一个节点*/ private int[] from; /**构造函数, 寻路算法,

图论训练之十二

夙愿已清 提交于 2019-12-01 19:21:16
bzOJ2654: tree Description 给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰 好有need 条白色边的生成树。 题目保证有解。 Input 第一行 V,E,need 分别表示点数,边数和需要的白色边数。 接下来E行,每行 s,t,c,col 表示这边的端点(点从0开始标号),边权,颜色 (0白色1黑色) 。 Output 一行表示所求生成树的边权和。 V<=50000,E<=100000, 所有数据边权为 [1,100] 中的正整数。 Sample Input 2 2 1 0 1 1 1 0 1 2 0 Sample Output 2 复习一下wqs二分 思路: wqs二分 显而易见,这是一道 最小生成树. ..... 但是问题在于其中有 黑白边及白边大小上 的要求。 根据kruskal的做法,我们发现选边的优先极取决于边权 , 如果我们能够将白边的边权进行扩大(缩小),那么就可以做到 控制白边数量 了。 接着,思考:当把所有白边都加上一个偏移量offset之后,可以求出一棵最小生成树, 再将答案减去树中**所有白边的数量*offset ,其实这就是一种合法的生成树。 offset过大导致选择的 白边太少 , 反之则太多**。 我们发现白边数量随offset的递增而递增,因此我们可以 二分答案 ,二分 offset的大小求解 。 code:

「图论」Tarjan

最后都变了- 提交于 2019-12-01 08:23:58
割点 对于一个无向图,如果把一个点删除后这个图的极大连通分量数增加了,那么这个点就是这个图的割点(又称割顶)。 如果尝试删除每个点,并且判断这个图的连通性,那么复杂度会特别的高。所以要介绍一个常用的算法:Tarjan。 首先,上一个图: 很容易的看出割点是 2,而且这个图仅有 2 这一个割点。 首先,按照 dfn 序给他打上时间戳(访问的顺序)。 这些信息被保存在一个叫做 dfn 的数组中。 还需要另外一个数组 low ,用它来存储不经过其入边(你有多个那么就看你遍历到了哪个)能到达的最小的时间戳。 例如 \(2\) 的话是 \(1\) , \(5\) 和 \(6\) 是 \(3\) 。 然后开始 DFS,判断某个点是否是割点的根据是:对于某个顶点 \(x\) ,如果存在至少一个顶点 \(y\) ( \(x\) 的出边),使得 \(low_v>=dfn_u\) ,即不能回到祖先,那么 \(x\) 点为割点。为什么这句话是对的呢?假设当前节点是在下面,他的入边在中间,如果他不经过他的入边访问不到上面的点,那么这个点一定是割点了。 另外,如果搜到了自己(在环中),如果他有两个及以上的出边,那么他一定是割点了,如果只有一个出边,那么把它删掉,不会有任何的影响。比如下面这个图,此处形成了一个环,从 \(1\) 走: 在访问 \(1\) 的出边时候,假设先 dfn 到了 \(2\)

【刷题】【图论】最优贸易【未完成】

拟墨画扇 提交于 2019-12-01 08:12:49
这题真是八仙过海 1>暴力,图上dp 看成一条条链,dp思路有点像spfa,有点记忆化的成分, 每次到一个点,如果 结果/向下传的最小值 变了,那么后面的状态才会改变, 所以这个剪枝 + f[rt]=max(f[rt] , f[pre] , val[rt]-mn ); 然后就写出代码 #include<cstdio> #include<cstdlib> #include<cstring> #include<queue> #include<cstring> using namespace std; int n,m; const int N=5e4+3,M=1e5+3; int tot,head[N]; struct node { int v,nx; }e[M<<1]; void add(int u,int v) { e[++tot].v =v,e[tot].nx =head[u],head[u]=tot; } inline int read() { int x=0;char c=getchar(); while(c<'0' || c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar(); return x; } int val[N],f[N],lst[N]; void dfs(int rt