有向图的强连通分量

强联通:两个点之间可以互相到达

如果某个图任意两个点都是强联通的,那么称这个图强联通

如果一个图的子图是强联通的,那么称这个图是强联通子图

一个图的极大强联通子图被称作强连通分量

有强联通分量意味着环

例:受欢迎的牛

如果有环,意味着这个环里的牛都互相喜欢

我们可以先求出环,然后把每一个环都看作一个点,这样整个图就变成了一个DAG(有向无环图)

看有几个点出度为0,如果大于一个点没有出边,就说明没有最受欢迎的牛

如果只有一个,那么强联通分量的大小就是答案

void tarjan(int u){
dfn[u]=++ind;
low[u]=dfn[u];
s[top++]=u;
in[u]=;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(dfn[v]==){//mei bian li dao, v zai zi shu li mian
tarjan(v);
low[u]=min(low[u],low[v]);
}else{//bian li dao le, v bu zai zi shu li mian
if(in[v]){//zai zhan li mian
low[u]=min(low[u],dfn[v]);
}
}
}
if(dfn[u]==low[u]){//fa xian scc
cnt_scc++;
while(s[top]!=u){//bu duan chu zhan
top--;
in[s[top]]=;
scc[s[top]]=cnt_scc;
}
}
}

完整代码:

#include<bits/stdc++.h>
using namespace std; int n,m; int cnt,head[]; struct edge
{
int to,nxt;
}edg[]; inline void add(int from,int to)
{
edg[++cnt].to=to;
edg[cnt].nxt=head[from];
head[from]=cnt;
} int dfn[],low[],ind,in[];
int s[],top;
int cnt_scc;
int scc[],cntscc[]; void tarjan(int x)
{
dfn[x]=++ind;
low[x]=dfn[x];
s[top++]=x;
in[x]=;
for(int i=head[x];i;i=edg[i].nxt)
{
int v=edg[i].to;
if(!dfn[v])
{
tarjan(v);
low[x]=min(low[x],low[v]);
}
else
{
if(in[v])
{
low[x]=min(low[x],dfn[v]);
}
}
}
if(dfn[x]==low[x])
{
cnt_scc++;
while(s[top]!=x)
{
top--;
in[s[top]]=;
scc[s[top]]=cnt_scc;
cntscc[cnt_scc]++;
}
}
} int out[];
int ans; int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
for(int i=;i<=n;i++)
{
for(int j=head[i];j;j=edg[j].nxt)
{
int k=edg[j].to;
if(scc[i]!=scc[k]) out[scc[i]]++;
}
}
for(int i=;i<=cnt_scc;i++)
{
if(!out[i])
{
if(!ans)
ans=i;
else
{
cout<<;
return ;
}
}
}
cout<<cntscc[ans];
}

求强联通分量:

首先想到dfs,我们不妨先看看dfs数

发现有向图中dfs树会有横叉边

显然的事实:一个强连通分量一定是dfs树上的连续的一块

我们定义两个数组

dfn[x]表示x是第几个被dfs到的数(时间戳)

low[x]表示当前节点以及他的子树所有出边所能连到的dfn值中最小的一个

如果某一个点的low和他的dfn相同,就意味着出现强联通分量,就把这个强连通分量拿去(没了)

用一个栈来实现,寻找low时只在栈里面找,弹出时不断从栈顶弹出直到弹出这个点

A gift

把g按照升序排序,枚举g0,跑最小生成树(然后就tle)O(m^2logm)

当我们再连一条新边时,会出现环,所以找到环上的最大的边然后删掉它,复杂度O(n)

总复杂度O(mn)

狼抓兔子

平面图的最小割等于对偶图的最短路

最小割:所有割中边权和最小的割

对偶图:边变成点,点变成边    平面图的每一个块变成一个点,每一条边变成垂直的一条边

#include<cstdio>
#include<cstring>
#define oo 0x3f
#define MAXN 2000001
using namespace std;
struct edge {
int v,to,next;
} e[MAXN*];
int dis[MAXN],q[MAXN],head[MAXN];
bool tag[MAXN];
int n,m,ne,x;
void insert(int u,int v,int w) {
ne++;
e[ne].to=v;
e[ne].next=head[u];
e[ne].v=w;
head[u]=ne;
}
void spfa() {
memset(dis,oo,sizeof(dis));
int t=,w=;
tag[]=;
q[w]=;
dis[]=;
while(t!=w) {
int u=q[t++];
tag[u]=;
if(t==MAXN) t=;
for(int i=head[u]; i; i=e[i].next) {
int v=e[i].to;
if(dis[v]>dis[u]+e[i].v) {
dis[v]=dis[u]+e[i].v;
if(tag[v]==) {
q[w++]=v;
tag[v]=;
if(w==MAXN) w=;
}
}
}
}
}
int main() {
scanf("%d%d",&n,&m);
int nm=(n*m-n-m+)<<;
for(int i=; i<=n; i++) {
for(int j=; j<m; j++) {
scanf("%d",&x);
if(i==) insert(j,nm+,x);
else if(i==n) insert(,(((n-)<<)-)*(m-)+j,x);
else insert(((i-)<<)*(m-)+j,(((i-)<<)-)*(m-)+j,x);
}
}
for(int i=; i<n; i++) {
for(int j=; j<=m; j++) {
scanf("%d",&x);
if(j==) insert(,((i<<)-)*(m-)+,x);
else if(j==m) insert(((i<<)-)*(m-),nm+,x);
else insert(((i-)<<)*(m-)+j-,((i<<)-)*(m-)+j,x);
}
}
for(int i=; i<n; i++) {
for(int j=; j<m; j++) {
scanf("%d",&x);
insert((((i-)<<)+)*(m-)+j,((i-)<<)*(m-)+j,x);
}
}
spfa();
printf("%d\n",dis[nm+]);
return ;
}

奶牛的旅行

0/1分数规划

二分答案+spfa判负环

最优比率生成树

抢掠计划

把强联通分量缩点

从点1开始跑一遍最长路spfa,在酒吧取max

奶牛接力跑

倍增floyd(floyd快速幂)

g[1][i][j]表示从i到j只经过一条边的最短路

如何转移到g[2][i][j]?

枚 举所有中点k,对于所有的k,g[2][i][j]表示min(g[1][i][k]+g[1][k][j])

同理也可以求出g[4][i][k]

所以g[p][i][j]=min(g[p/2][i][k]+g[p/2][k][j])

g[3][i][j]=min(g[2][i][k]+g[1][k][j])

和快速幂的关系:用类似于快速幂的方法将其分解

while(b){
if(b&){
memset(f,0x3f,sizeof(f));
for(int k=;k<=n;k++){
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
f[i][j]=min(f[i][j],ret[i][k]+g[k][j]);
}
}
}
memcpy(ret,f,sizeof(f));
}
memset(f,0x3f,sizeof(f));
for(int k=;k<=n;k++){
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
f[i][j]=min(f[i][j],g[i][k]+g[k][j]);
}
}
}
memcpy(g,f,sizeof(f));
   b>>=1;
} print(ret[S][E])

Destroying road

  1. 两条最短路不交叉  删掉的边的数量:m-dis[s1][t1]-dis[s1][t2]
  2. 两条最短路有公共部分

Bfs求最短路

匈牙利算法:配对

int g[N][N];
int lk[N];// mei zi xi huan na ge nan de
bool vis[N];//zhe yi lun, mei zi you mei you bei jiao huan bool find(int x){
for(int i=;i<=n;i++){
if(!vis[i]&&g[x][i]){
vis[i]=;
if(lk[i]==||find(lk[i])){
lk[i]=x;
return ;
}
}
}
return ;
} for(int i=;i<=n;i++){
memset(vis,,sizeof(vis));
if(find(i)){
hunpei++;
}else{
break;
}
}

差分约束系统

最小化最长路

例题:糖果

qbzt day4 下午的更多相关文章

  1. Day4下午解题报告

    预计分数:30+30+0=60 实际分数:30+30+10=70 稳有个毛线用,,又拿不出成绩来,, T1 https://www.luogu.org/problem/show?pid=T15626 ...

  2. Day4下午

    不会啊. T1 找规律: 辗转相减,加速. #include<iostream> #include<cstring> #include<cstdio> #inclu ...

  3. qbzt day6 下午 模拟赛

    我太菜了 T2 给定一张有向图,每个点有点权.试找到一条路径,使得该路径上的点权最 大值减去点权最小值最大,问这个差最大是多少.   话说这个题第一个想到的思路是tarjan缩点+拓扑排序来着... ...

  4. qbzt day5 下午

    农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他的奶牛们享 ...

  5. qbzt day4 上午

    图论 最短路:dijkstra   spfa   floyd 最小生成树:kruskal 连通性:bfs/dfs    tarjan(强连通分量) 其它:拓扑排序    LCA 齿轮: 图的dfs树只 ...

  6. qbzt day3 下午(好难)

    内容提要 有关数据结构的例题 求逆序对数 统计每个数前面有多少比他大的数 开数组表示这个数之前0~9这些数出现了几次 动态将某个点加一,动态求前缀和 用树状数组 如果数太大了怎么办? 离散化 步骤:先 ...

  7. qbzt day2 下午

    内容提要 高精 矩阵 筛法 先是高精除法 注意细节 高精度开方:神奇的竖式 以小数点为分界线,每两个位砍一刀 87654.321-->08|76|54|.32|1 大概就是先对第一位开方,然后相 ...

  8. WC2017 游记

    你若安好,便是晴天. 其实本来是有一个写的比较详细的游记的……然而后来给断了,懒得补上了,简单一点好了. Day 0 早早爬起来去赶高铁…… 路上没太多可以写的……坐高铁的时候想起来了一些不开心的事情 ...

  9. Alpha冲刺! Day4 - 磨刀

    Alpha冲刺! Day4 - 磨刀 今日已完成 晨瑶:和大家交流了一下,反思这阶段团队遇到的问题. 昭锡:今天跟学长交流了点问题,学习了Gson使用. 永盛:Gravel 数据库重新设计. 立强:看 ...

随机推荐

  1. gcc编译工具生成动态库和静态库

    一. 库的分类 1.1. 静态库(.a) 1.1.1. 静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大.所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 1. ...

  2. tensorflow学习笔记六----------神经网络

    使用mnist数据集进行神经网络的构建 import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from ...

  3. Python作图包含type3字体解决方案

    1. 解决方案 matplotlib.rcParams[‘text.usetex’] = True

  4. 如何将一个.NET Core类库发布到NuGet

    包治百病 | 如何将一个.NET Core类库发布到NuGet 写文章 包治百病 | 如何将一个.NET Core类库发布到NuGet Edi Wang发表于汪宇杰博客订阅 77 NuGet是.NET ...

  5. spark 在启动的时候出现JAVA_HOME not set

    解决方法:在sbin目录下的spark-config.sh 中添加对应的jdk 路径,然后使用scp -r 命令复制到各个worker节点

  6. 百度网盘SVIP不限速Mac破解版(亲测可用)

    百度网盘SVIP不限速Mac破解版(亲测可用),按照教程一步一步来就可以了,链接如下: https://mac.orsoon.com/Mac/166358.html?id=ODY0MDA2Jl8mMT ...

  7. Red Hat Enterprise Linux 8.0 安装

    Red Hat Enterprise Linux 8.0 安装 本次安装通过使用VMware Workstation 15 pro 进行. 1.新建虚拟机 2.点击首页的创建新的虚拟机,或者点击标签栏 ...

  8. GNU ARM eclipse 安装--Linux 版本

    官方网站:https://gnu-mcu-eclipse.github.io/ 1. 工具链安装 1.1 xpm 安装 安装 nodejs: sudo apt-get install nodejs s ...

  9. java 通过反射获取数组

    1.创建数组.设置数组元素.访问数组 一维数组: 多维数组: public Class<?> getComponentType() 返回表示数组组件类型的 Class.如果此类不表示数组类 ...

  10. ionic icon(图标)

    https://www.runoob.com/ionic/ionic-icon.html ionic 也默认提供了许多的图标,大概有 700 多个,针对 Android 和 iOS 有不同的样式.