2020-11-08周总结

1 tarjan算法的应用

tarjan算法中
dfn[] :每个点的dfs序
low[]:每个点能到达的dfs序最小的节点的dfs序

1.将强连通分量缩点变成DAG
技巧:
(1)将某个DAG补成强连通图 需要加的边为 max(入度,出度).
(2)做完 Tarjan 算法后,按编号递减的顺序就是拓扑序.

int scc_cnt,id[N],siz[N];
int stk[N],top;
bool instk[N];
int w[N],sum[N];
void tarjan(int x){
    dfn[x] = low[x] = ++ timestamol;
    stk[++top] = x,instk[x] = 1;
    for(int i = h[x];i;i = ne[i]){
        int y = e[i];
        if(!dfn[y]){//y点未被遍历过
            tarjan(y);
            low[x] = min(low[x],low[y]);//计算能达到的最小时间戳
        }
        //y点在栈中  说明还没出栈 是dfs序比当前点y小的
        //则其 1要么是横插边(左边分支的点)
        //     2要么是y的祖宗节点
        else if(instk[y]) low[x] = min(low[x],dfn[y]); //栈代表当前未被搜完的强连通分量的所有点 , 在同一scc中 可以取min
    }
    if(dfn[x] == low[x]){//x是这个scc的最高点,把这个scc缩点
        scc_cnt++;
        int y;
        do{
            y = stk[top--];
            instk[y] = 0;
            id[y] = scc_cnt;
        }while(x != y);
    }
}

2.求割点

bool cut[N];
void tarjan(int x,int pr){
    dfn[x] = low[x] = ++timestamp;
    int child = 0; //子节点
    for(int i = h[x];i;i = ne[i]){ //遍历每一个相邻的点
        int y = e[i]; 
        if(!dfn[y]){//这个点没有被遍历过
            tarjan(y,pr);
            low[x] = min(low[x],low[y]);
            if(low[y] >= dfn[x] && x != pr){ //当前节点的这个子节点dfs序大于等于当前节点的dfs序 且不是连通块第一个访问的节点
                cut[x] = 1;
            }
            if(x == pr) child++; 
        }
        low[x] = min(low[x],dfn[y]);
    }
    if(child >= 2 && x == pr){//开始的第一个点就是割点 特判
        cut[x] = 1;
    }
}

3.求桥和边的双连通分量

bool bridge[M];
void tarjan(int x,int from){ //from 是边
    dfn[x] = low[x] = ++timestamp;
    stk[++top] = x;
    for(int i = h[x];i;i = ne[i]){ //i是边 
        int y = e[i]; // y是x的临点
        if(!dfn[y]){
            tarjan(y,i);
            low[x] = min(low[x],low[y]);
            if(dfn[x] < low[y]){
                bridge[i] = bridge[i ^ 1] = 1; //成对变换
            }
        }
        else if(i != (from ^ 1)){
            low[x] = min(low[x],dfn[y]);
        }
    }
    if(dfn[x] == low[x]){
        dcc_cnt++;
        int y;
        do{
            y = stk[top--];
            id[y] = dcc_cnt;
        }while(y != x);
    }
}

2二分图

1.染色法求二分图
一个图是二分图 <=> 图中不存在奇数环 <=> 染色法过程中不存在矛盾

bool dfs(int x,int c,int mid){
    color[x] = c;
    for(int i = h[x];i;i = ne[i]){
        int y = e[i];
        if(w[i] <= mid) continue; // 在最大范围内进行染色
        if(color[y]){
            if(color[y] == c) return 0; //有相同染色不成立
        }
        else if(!dfs(y,3 - c,mid)) return 0; // 不是异色不成立
    }
    return 1; //成立了
}

2.求二分图最大匹配
匈牙利算法 时间复杂度O(mn)

bool vis[N];
int match[N];
bool dfs(int x){
    for(int i = h[x];i;i = ne[i]){
        int y = e[i];
        if(!vis[y]){
            vis[y] = 1;
            if(!match[y] || dfs(match[y])){
                match[y] = x;
                return 1;
            }
        }
    }
    return 0;
}
    for(int i = 1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(dfs(i)) ans++;
    }

二分图匹配的模型有两个要素
1.节点能分为两个集合 , 每个集合内部有0条边
2.每个节点只能与一条匹配边相连

3其他的一些

求取模的组合数

const int mod = 998244353;
int pow(int x,int n){
    int ans = 1;
    while(n){
    if(n % 2)ans = ans*x%mod;
    x = x*x%mod;
    n /= 2;
    }
    return ans;
}
int C(int n,int m){
    int up = 1,dn = 1;
    for(int i = 1;i <= m;++i){
    up = up*(n+1-i)%mod;
    dn = dn*i%mod;
    }
    return up*pow(dn,mod-2)%mod;
}

构造两两不互质的一组数,最常见的有两种:

  1. 2 x 3 ,3 x 5,5 x 7,7 x 9,…,
  2. 2 x 1,2 x 2,2 x 3,2 x 4 …

刷题截屏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值