zoukankan      html  css  js  c++  java
  • 图论1 Tarjan算法

    强连通分量

    模板(强联通分量个数+缩点)

    #include<iostream>
    #include<cstdio>
    #define MAXn 100000
    #define MAXm 2000000
    using namespace std;
    int dfn[MAXn],low[MAXn],head[MAXm],st[MAXn],belong[MAXn];
    bool in_st[MAXn];
    int ans,n,m,num,s_num,cnt,group_num;
    struct node{
        int to,pre;
    }e[MAXm];
    void Insert(int from,int to){
        e[++num].pre=head[from];
        e[num].to=to;
        head[from]=num;
    }
    void group(int u){
        cnt++;st[++s_num]=u;dfn[u]=low[u]=cnt;in_st[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(!dfn[v]){
                group(v);
                if(low[v]<low[u])low[u]=low[v];
            }
            else if(dfn[v]<low[u])
                if(in_st[v])
                low[u]=dfn[v];
        }
        if(dfn[u]==low[u]){
            group_num++;
            while(st[s_num]!=u){
                in_st[st[s_num]]=0;
                belong[st[s_num]]=group_num;
                s_num--;
            }
            in_st[u]=0;s_num--;
            belong[u]=group_num;
        }
    }
    int main(){
        freopen("Tarjan_group.txt","r",stdin);
        scanf("%d%d",&n,&m);int x,y;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            Insert(x,y);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i])group(i);
        }
        for(int i=1;i<=n;i++){
            printf("%d ",belong[i]);
        }printf("
    %d",group_num);
    }
    Tarjan_group模板

    例题

    poj3114  Countries in War

    跑一边强连通分量,搞出缩点,求缩点间的最短路

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define maxm 250010
    #define maxn 510
    int head[maxm],dfn[maxn],low[maxn],st[maxn],belong[maxn],blong[maxn][maxn];
    int n,m,num,order,cnt,s_num,num_g,dis[maxn][maxn];
    int nw[510][510];
    bool in_st[maxn];
    struct node{
        int to,v,pre;
    }e[maxm];
    void Insert(int from,int to,int v){
        e[++num].to=to;
        e[num].pre=head[from];
        e[num].v=v;
        head[from]=num;
    }
    void group(int u){
        cnt++;dfn[u]=low[u]=cnt;st[++s_num]=u;in_st[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(!dfn[v]){
                group(v);
                if(low[v]<low[u])low[u]=low[v];
            }
            else if(dfn[v]<low[u])
                if(in_st[v])low[u]=dfn[v];
        }
        if(low[u]==dfn[u]){
            num_g++;
            while(st[s_num]!=u){
                blong[num_g][++blong[num_g][0]]=st[s_num];
                belong[st[s_num]]=num_g;
                in_st[st[s_num]]=0;
                s_num--;
            }belong[u]=num_g;
            blong[num_g][++blong[num_g][0]]=u;
            in_st[u]=0;s_num--;
        }
    }
    int main(){
        freopen("Tarjan_group.txt","r",stdin);
        int nm,nn;
        while(1){
            cin>>n>>m;
            if(n==0&&m==0)break;
            memset(dfn,0,sizeof(dfn));
            memset(head,0,sizeof(head));
            memset(low,0,sizeof(low));
            memset(st,0,sizeof(st));
            memset(e,0,sizeof(e));
            memset(belong,0,sizeof(belong));
            memset(blong,0,sizeof(blong));
            num_g=0;s_num=0;cnt=0;
            int x,y,z;
            memset(nw,127/3,sizeof(nw));
            memset(dis,127/3,sizeof(dis));
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&x,&y,&z);
                Insert(x,y,z);
                nw[x][y]=z;
            }
            for(int i=1;i<=n;i++){
                if(!dfn[i])group(i);
            }
            
            /*for(int i=1;i<=n;i++)
            cout<<belong[i]<<' ';cout<<endl<<endl;*/
            for(int i=1;i<=n;i++){
                dis[i][i]=0;
                nw[i][i]=0;
            }
            for(int k=1;k<=n;k++){
                for(int i=1;i<=n;i++){
                    for(int j=1;j<=n;j++){
                        if(i!=j&&i!=k&&k!=j)
                        nw[i][j]=min(nw[i][j],nw[i][k]+nw[k][j]);
                    }
                }
            }
            for(int i=1;i<=num_g;i++){
                for(int j=1;j<=num_g;j++){//找到两个缩点 
                    if(i!=j){
                        for(int k=1;k<=blong[i][0];k++){
                            for(int l=1;l<=blong[j][0];l++){
                                if(k!=l)
                                dis[i][j]=min(dis[i][j],nw[blong[i][k]][blong[j][l]]);
                            }
                        }
                    }
                }
            }
            int p;
            scanf("%d",&p);
            for(int i=1;i<=p;i++){
                scanf("%d%d",&x,&y);
                if(dis[belong[x]][belong[y]]>=707406378)cout<<"Nao e possivel entregar a carta"<<endl;
                else cout<<dis[belong[x]][belong[y]]<<endl;
            }
        }
    }
    TLE
    #include<cstring>  
    #include<cstdio>
    #include<iostream>
    #define Max 505  
    using namespace std;
    int map[Max][Max];  
    struct Edge{  
        int to,w;  
        int next;  
    }edge[Max * Max];   
    int head[Max],tol;  
    void add(int u,int v,int w){  
        edge[tol].to=v;  
        edge[tol].w=w;  
        edge[tol].next=head[u];  
        head[u]=tol++;  
    } 
    int dfn[Max],low[Max],Stack[Max],belong[Max];  
    int bcnt,time,top,instack[Max];  
    void tarjan(int u){  
        dfn[u]=low[u]=++time;  
        Stack[top++]=u;  
        instack[u]=true;  
        for(int i=head[u];i!=-1;i=edge[i].next){  
            int v=edge[i].to;  
            if(!dfn[v]){  
                tarjan(v);  
                low[u] = min(low[u], low[v]);  
            }  
            else{  
                if( instack[v])  
                    low[u] = min(low[u], dfn[v]);  
            }  
        }  
        int v;  
        if(low[u] == dfn[u]){  
            bcnt++;  
            do{  
                v = Stack[--top];  
                instack[v] = false;  
                belong[v] = bcnt;  
            }while(u != v);  
        }  
    }  
    int main(){  
        int n,m;  
        int v,u,w;  
        while(~scanf("%d%d", &n,&m)){  
            if(!n && !m) break;  
            memset(head,-1,sizeof(head));  
            tol=0;  
            for(int i=1;i<=m;i++){  
                int u,v,w;  
                scanf("%d%d%d",&u,&v,&w);  
                add(u,v,w);  
            }  
            memset(dfn,0,sizeof(dfn));  
            memset(low,0,sizeof(low));  
            top=time=bcnt=0;  
            for(int i=1;i<=n;i++)  
                if(!dfn[i])  
                  tarjan(i);  
              for(int i=1;i<=n;i++){  
                  for(int j=1;j<=n;j++)  
                    if(i==j)  
                    map[i][j]=0;  
                  else map[i][j]=0x3f3f3f3f;  
              }  
      
              for(u=1;u<=n;u++)  {  
                  for(int j=head[u];j!=-1;j=edge[j].next)  {  
                      v=edge[j].to;  
                      w=edge[j].w;  
                      if(belong[u]!=belong[v])  
                        map[belong[u]][belong[v]]=min(map[belong[u]][belong[v]],w);  
                  }  
              }  
              for(int k=1;k<=bcnt;k++){  
                  for(int i=1;i<=bcnt;i++){  
                      for(int j=1;j<=bcnt;j++)  
                        if(map[i][j]>map[i][k]+map[k][j])  
                          map[i][j]=map[i][k]+map[k][j];  
                  }  
              }  
              int t;  
              scanf("%d",&t);  
              while(t--){  
                  scanf("%d%d",&u,&v);  
                  if(map[belong[u]][belong[v]] == 0x3f3f3f3f)  
                    printf("Nao e possivel entregar a carta
    ");  
                  else  
                  printf("%d
    ",map[belong[u]][belong[v]]);  
              }  
              printf("
    ");  
        }  
        return 0;  
    }    
    AC

    poj1236Network of Schools

    题意:一个包含1-n号学校的网络,每个学校有个软件分发列表,当学校拿到软件时会把软件分发给列表里的学校。 
    问1:一个新软件出现时初始化情况至少需要给多少个学校才能让它到达整个网络? 
    问2:至少需要添加多少个名单才能使从任意一个学校开始分发都能充满整个网络? 

    也就是: 
    —给定一个有向图,求:

    1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点

    2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点

    DAG上面有多少个入度为0的顶点,问题1的答案就是多少 
    在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少 

    加边的方法:假定有 n 个入度为0的点,m个出度为0的点,max(m,n)就是第二个问题的解

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define maxn 110
    #define maxm (maxn*(maxn - 1)/2)
    int n,num,cnt,num_g,num_in0,num_out0;
    int in[maxn],out[maxn],head[maxm],belong[maxn],dfn[maxn],low[maxn],st[maxn],s_num;
    int blong[maxn][maxn],nmp[maxn][maxn];
    bool s_in[maxn],vis[maxn][maxn];
    struct node{
        int to,pre;
    }e[maxm];
    void Insert(int from,int to){
        e[++num].pre=head[from];
        e[num].to=to;
        head[from]=num;
    }
    void group(int u){
        cnt++;dfn[u]=low[u]=cnt;st[++s_num]=u;s_in[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(dfn[v]==0){
                group(v);
                low[u]=min(low[u],low[v]);
            }
            else if(dfn[v]){
                /*if(s_in[v])*/low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            num_g++;
            while(st[s_num]!=u){
                s_in[st[s_num]]=0;
                belong[st[s_num]]=num_g;
                blong[num_g][++blong[num_g][0]]=st[s_num];
                s_num--;
            }
            s_num--;belong[u]=num_g;
            blong[num_g][++blong[num_g][0]]=u;
        }
    }
    int main(){
        freopen("1236.txt","r",stdin);
        scanf("%d",&n);int a;
        for(int i=1;i<=n;i++){
            while(1){
                scanf("%d",&a);
                if(a==0)break;
                Insert(i,a);
            }
        }
        for(int i=1;i<=n;i++){
            if(dfn[i]==0)group(i);
        }
        
        /*for(int i=1;i<=num_g;i++){//枚举每个缩点 
            for(int j=1;j<=blong[i][0];j++){//枚举缩点里的每个点 
                int u=i;
                for(int k=head[blong[i][j]];k;k=e[k].pre){
                    int v=belong[e[k].to];
                    if(vis[u][v]==0&&v!=u){
                        vis[u][v]=1;in[v]++;out[u]++;
                    }
                }
            }
        }*/
        for(int u=1;u<=n;u++){
            for(int i=head[u];i;i=e[i].pre){
                int v=e[i].to;
                if(belong[u]!=belong[v]){
                    in[belong[v]]++;
                    out[belong[u]]++;
                }
            }
        }
        for(int i=1;i<=num_g;i++){
            if(in[i]==0)num_in0++;
            if(out[i]==0)num_out0++;
        }
        cout<<num_in0<<endl;
        if(num_g==1)cout<<0;
        else cout<<max(num_in0,num_out0);
        return 0;
    }
    wa
    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define maxn 110
    #define maxm (maxn*(maxn - 1)/2)
    int n,num,cnt,num_g,num_in0,num_out0;
    int in[maxn],out[maxn],head[maxm],belong[maxn],dfn[maxn],low[maxn],st[maxn],s_num;
    int blong[maxn][maxn],nmp[maxn][maxn];
    bool s_in[maxn],vis[maxn][maxn];
    struct node{
        int to,pre;
    }e[maxm];
    void Insert(int from,int to){
        e[++num].pre=head[from];
        e[num].to=to;
        head[from]=num;
    }
    void group(int u){
        cnt++;dfn[u]=low[u]=cnt;st[++s_num]=u;s_in[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].to;
            if(dfn[v]==0){
                group(v);
                low[u]=min(low[u],low[v]);
            }
            else if(dfn[v]){
                if(s_in[v])low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            num_g++;
            while(st[s_num]!=u){
                s_in[st[s_num]]=0;
                belong[st[s_num]]=num_g;
                blong[num_g][++blong[num_g][0]]=st[s_num];
                s_num--;
            }
            s_num--;belong[u]=num_g;
            blong[num_g][++blong[num_g][0]]=u;
            s_in[u]=0;
        }
    }
    int main(){
        scanf("%d",&n);int a;
        for(int i=1;i<=n;i++){
            while(1){
                scanf("%d",&a);
                if(a==0)break;
                Insert(i,a);
            }
        }
        for(int i=1;i<=n;i++){
            if(dfn[i]==0)group(i);
        }
        for(int u=1;u<=n;u++){
            for(int i=head[u];i;i=e[i].pre){
                int v=e[i].to;
                if(belong[u]!=belong[v]){
                    in[belong[v]]++;
                    out[belong[u]]++;
                }
            }
        }
        for(int i=1;i<=num_g;i++){
            if(in[i]==0)num_in0++;
            if(out[i]==0)num_out0++;
        }
        cout<<num_in0<<endl;
        if(num_g==1)cout<<0;
        else cout<<max(num_in0,num_out0);
        return 0;
    }
    AC
  • 相关阅读:
    Kotlin基本语法笔记3之定义类、继承及创建实例
    Kotlin基本语法笔记2之类型检测及自动类型转换、循环
    Kotlin基本语法笔记之函数、变量的定义及null检测
    C++笔记之外部类访问内部类的私有成员
    正则表达式之不区分大小写的匹配
    springMVC之helloworld
    数组学习
    反射reflect
    JSP学习
    自己做的菜
  • 原文地址:https://www.cnblogs.com/thmyl/p/6641752.html
Copyright © 2011-2022 走看看