强连通
定理:有向图中存在某点的入度或出度为零时,这张有向图不是强连通图
DCC缩点后建立一棵树, 树中的所有边都是桥。
一般要把缩点后的树建成
for(int i = 2;i<=z;i++){
int a = id[e[i]],b = id[e[i^1]];
if(a != b){
add(rh,a,b),add(rh,b,a);
}
}
建新图 + 建桥
for(int i = 2;i<=z;i += 2){
int a = e[i],b = e[i^1];
if(id[a] != id[b]){ //如果是桥
ans++;
bridge[1 + idx] = bridge[2 + idx] = 1;
add(rh,id[a],id[b]),add(rh,id[b],id[a]);
}
}
完全图问题中加边或删边 正向加边 = 反向删边
树的直径
一般用于一棵树构成最大环
树的直径dp求法
int diam;
int d[N];
bool vis[N];
void dfs(int x){
vis[x] = 1;
for(int i = h[x];i;i = ne[i]){
int y = e[i];
if(vis[y]) continue;
dfs(y);
diam = max(diam,d[x] + d[y] + w[i]);
d[x] = max(d[x],d[y] + w[i]);
}
}
两遍dfs的做法 (这种做法可以求出直径的路径)
int maxdep,num;
int dep[N],fa[N],m_dep[N];
bool vis[N];
int ans[N];
void dfs(int x,int pr){
if(dep[x] > maxdep){
maxdep = dep[x];
num = x;//最深的一个点
}
for(int i = h[x];i;i = ne[i]){
int y = e[i];
if(y == pr) continue;
dep[y] = dep[x] + 1;
fa[y] = x;//记录父节点可以 找到最长的这条边
dfs(y,x);
}
}
求路径时 从某一个端点出发 然后一直走将路径用一个bool数组标记
找出直径的路径 方便对这条路径进行修改
A = mdepv;
dfs(A,-1);
B = mdepv;
while(fa[B] > 0){
st[B] = 1;
B = fa[B];
}
匹配问题
判断二分图:
1.能分为两个独立集合,每个集合内不连边
2.每个节点只能与1条边匹配
二分图方案数 :设黑q个 白p个
交换黑白后 一共用2^q + 2^p 方案数
模型特点:每条边上有两个端点,至少选一个
边覆盖:用边把所有的点覆盖
最小边覆盖 = V - 最大匹配
点覆盖:用点把所有的边全给覆盖
最小点覆盖 = 最大匹配
(需要求传递闭包得到一个新图)
独立集:两点之间没有边相连
最大独立集 = V - 最大匹配
棋盘模型中 只需要建单向边 一般用邻接矩阵
将匹配边删除最好在邻接矩阵中进行
刷题截图
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/bd8f1b6609951d95725f24fdb84bae5f.png#pic_center
![](https://i-blog.csdnimg.cn/blog_migrate/ae70b866d35ce269913b3d5b59f517d9.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/bd8f1b6609951d95725f24fdb84bae5f.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/a86e3ce35e860cdb6a53f1c5c00c4863.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/9ca75b6ed7c780c77eb1fe14b92dc0f7.png#pic_center)