kuangbin-连通图

 小结:

1,tarjan求有向图强联通请注意处理回退边时,只能把还在栈中元素更新。
2,有重边时,注意不要传father,要传非相邻边。
3,

A - Network of Schools

 POJ - 1236 

两个问题:有向图,最小点覆盖,最小边使得图联通。

最小点覆盖 :即为入度为0强联通个数。

最小边 : 

图中入度为0的强联通数为 a ,出度为0的强联通为 b 。那么让出度为0 分量去 连 入度为 0 的分量一定是最优的,

即max( a, b )

但要注意强联通算法的更新low值。

#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
typedef long long ll;
// const ll MOD=998244353;
const int N=1e5+5;
int dfn,n,ecnt,SCC;
int sccno[N],num[N],low[N],belong[N],in[N],out[N],head[N];
bool instack[N];
struct edge{int v,next;}e[N];
void add(int u,int v){
e[ecnt].v=v;e[ecnt].next=head[u];head[u]=ecnt++;
}
stack<int>sta;
void init(){
    ecnt=SCC=dfn=0;
    memset(head,-1,sizeof head);
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
    memset(belong,0,sizeof belong);
    memset(low,0,sizeof low);
    memset(num,0,sizeof num);
    memset(sccno,0,sizeof sccno);
    while(!sta.empty())sta.pop();
}
void tarjan(int u){
    num[u]=low[u]=++dfn;
    sta.push(u);
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(!num[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!belong[v])low[u]=min(low[u],num[v]); 
    }
    if(num[u]==low[u]){
    SCC++;
    while(1){
        int v=sta.top();sta.pop();
        belong[v]=SCC;
        if(v==u)break;
        }
    }
}
void solve(){
    for(int i=1;i<=n;i++)if(!num[i])tarjan(i);
    for(int u=1;u<=n;u++){
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(belong[u]!=belong[v]){
                out[ belong[u] ]++;
                in[ belong[v] ]++;
            }
        }
    }
    int a=0,b=0;
    for(int i=1;i<=SCC;i++){
    if(in[i]==0)a++;
    else if(out[i]==0)b++;
    }
    if(SCC==1)cout<<1<<endl<<0<<endl;
    else cout<<a<<endl<<max(a,b)<<endl;
}
int main(){
    init();
    scanf("%d",&n);
    for(int u=1,v;u<=n;u++){
        while(~scanf("%d",&v),v){
        add(u,v);
        }
    }
    solve();
    system("pause");
    return 0;
}
View Code

 

D - Network

 POJ - 3694 

动态求SCC个数。

对于一张图,跑一遍tarjan,生成一颗树,树边一定是割边,当新加入边时,那么 u ,v 到 lca 的边都变成非桥,暴力更新即可。

听说压点更快,少了在一个强联通的时间。

#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
typedef long long ll;
const ll MOD=998244353;
const int N=1e5+5;
int dfn,n,m,ecnt,SCC;
struct edge{int v,next;}e[N*10];
int head[N],low[N],num[N],dep[N],bridge[N],pre[N];
void init(){
    memset(head,-1,sizeof head);
    memset(low,0,sizeof low);
    memset(num,0,sizeof num);
    memset(dep,0,sizeof dep);
    memset(bridge,0,sizeof bridge);
    memset(pre,0,sizeof pre);
    SCC=ecnt=dfn=0;
}
void add(int u,int v){
e[ecnt].v=v;e[ecnt].next=head[u];head[u]=ecnt++;
}
void tarjan(int u,int fa){
    low[u]=num[u]=++dfn;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa)continue;
        if(!num[v]){
            dep[v]=dep[u]+1;
            pre[v]=u;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>num[u])bridge[v]=1,SCC++;
        }
        else low[u]=min(low[u],num[v]);
    }
}
void work(int u,int v){
    while(dep[u]>dep[v]){
    if(bridge[u]){bridge[u]=0,SCC--;}
    u=pre[u];
    }
    while(dep[u]<dep[v]){
    if(bridge[v]){bridge[v]=0,SCC--;}
    v=pre[v];
    }
    while(u!=v){
    if(bridge[u]){SCC--;bridge[u]=0;}
    if(bridge[v]){SCC--;bridge[v]=0;}
    u=pre[u];
    v=pre[v];
    }
            printf("%d\n",SCC);
}
int main(){
    int kase=0;
    while(~scanf("%d %d",&n,&m),n+m){
        init();
        for(int i=1,u,v;i<=m;i++){
            scanf("%d %d",&u,&v);
            add(u,v);add(v,u);
        }
        tarjan(1,-1);
        int u,v,q;scanf("%d",&q);
        if(kase)puts("");
        printf("Case %d:\n",++kase);
        while(q--){
            scanf("%d %d",&u,&v);
            // add(u,v);add(v,u);
            work(u,v);
        }

    }
    // system("pause");
    return 0;
}
View Code

 

E - Redundant Paths

 POJ - 3177

题意:给你一张图,新增加一些边,使得图成为边双联通,但是图有重边,
解法:tarjan一遍,注意处理回退边时只能传相邻边,传father就gg ,因为有重边,
然后统计叶子节点个数,连边解决。

#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
typedef long long ll;
const ll MOD=998244353;
const int N=1e5+5;
int top=0,dfn,n,m,ecnt,SCC;
struct edge{int v,next;}e[N*10];
int head[N],low[N],num[N],out[N],in[N],belong[N];
// stack<int>stk;
int stk[N];
void init(){
    memset(head,-1,sizeof head);
    memset(low,0,sizeof low);
    memset(num,0,sizeof num);
    memset(belong,0,sizeof belong);
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
    SCC=ecnt=dfn=top=0;
    // while(!stk.empty())stk.pop();
}
void add(int u,int v){
e[ecnt].v=v;e[ecnt].next=head[u];head[u]=ecnt++;
}
void tarjan(int u,int fa){
    num[u]=low[u]=++dfn;
    // stk.push(u);
    stk[++top]=u;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if( (i^1) ==fa)continue;
        if(!num[v]){
            tarjan(v,i);
            low[u]=min(low[u],low[v]);
        }
        else if(!belong[v])low[u]=min(low[u],num[v]); 
    }
    if(num[u]==low[u]){
      SCC++;
    while(1){
        int v=stk[top];top--;
        // int v=stk.top();stk.pop();
        belong[v]=SCC;
        if(v==u)break;
        }
    }
}
int main(){
        // while(scanf("%d %d",&n,&m)){    
        scanf("%d %d",&n,&m);
        init();
        for(int i=1,u,v;i<=m;i++){
            scanf("%d %d",&u,&v);
            add(u,v);add(v,u);
        }

        for(int i=1;i<=n;i++)if(!num[i])tarjan(i,-1);
        for(int u=1;u<=n;u++){
            for(int i=head[u];~i;i=e[i].next){
                int v=e[i].v;
                if(belong[u]!=belong[v]){
                    out[ belong[u] ]++;
                    in[ belong[v] ]++;
                }
            }
        }
    int ans=0;
    for(int i=1;i<=SCC;i++)if(in[i]==1)ans++;
        ans=(ans+1)/2;
    printf("%d\n",ans);
    // }
    system("pause");
    return 0;
}
// 题意:给你一张图,新增加一些边,使得图成为边双联通,但是图有重边,
// 解法:tarjan一遍,注意处理回退边时只能传相邻边,传father就gg ,因为有重边,
// 然后统计叶子节点个数,连边解决。
View Code

 

H - Prince and Princess

 HDU - 4685 

题意:就是让你求,保证最大的二分图匹配的,每个点的匹配情况。

 

posted @ 2020-04-10 23:57  无声-黑白  阅读(188)  评论(0编辑  收藏  举报