程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 注意縮點後新建的圖的頂點數可能達到2*n-1

注意縮點後新建的圖的頂點數可能達到2*n-1

編輯:C++入門知識

模板


[cpp]
#include <cstdio>  
#include <cstring>  
#include <vector>  
#include <stack>  
#include <algorithm>  
#define N 2000    //注意縮點後新建的圖的頂點數可能達到2*n-1  
#define M 600000  //縮點新建的圖一定是樹  
using namespace std; 
 
struct Edge{ 
    int u,v,id,next; 
}edge[M*2]; 
 
int head[N],head2[N],cnt; 
int dfn[N],low[N],color[N],depth,c,b;   //color數組指示每個割點或者點雙連通分支的在新圖的標號,割點標號均>=c  
int cut[N];  //cut不為0表示是割點,分成cut+1塊  
stack<int>ss; 
vector<int>dpt[N];          //每個點連通分支所包含的節點  
vector<int>node_bcc[N];     //每個節點所屬的點連通分支  
int edge_belong[N];         //每條邊所屬的點連通分支  
 
void addedge(int u,int v,int id,int * head){ 
    edge[cnt].u=u; 
    edge[cnt].v=v; 
    edge[cnt].id=id; 
    edge[cnt].next=head[u]; 
    head[u]=cnt++; 
    edge[cnt].u=v; 
    edge[cnt].v=u; 
    edge[cnt].id=id; 
    edge[cnt].next=head[v]; 
    head[v]=cnt++; 

 
void init(){ 
    memset(head,-1,sizeof(head)); 
    memset(head2,-1,sizeof(head2)); 
    memset(dfn,0,sizeof(dfn)); 
    memset(color,0,sizeof(color)); 
    memset(cut,0,sizeof(cut)); 
    depth=c=cnt=0; 
    for(int i=0;i<N;i++) dpt[i].clear(),node_bcc[i].clear(); 
    memset(edge_belong,0,sizeof(edge_belong)); 

 
void tarjan(int u,int fa){ 
    int i,j; 
    dfn[u]=low[u]=++depth; 
    for(i=head[u];i!=-1;i=edge[i].next){ 
        int v=edge[i].v; 
        if(v==fa)continue; 
        if(dfn[v]==0){ 
            ss.push(i); 
            tarjan(v,u); 
            low[u]=min(low[u],low[v]); 
            if(dfn[u]<=low[v]){ 
                cut[u]++; 
                c++; 
                do{ 
                    j=ss.top(); 
                    //printf("%d-%d ",edge[j].u,edge[j].v);  
                    ss.pop(); 
                    edge_belong[edge[j].id]=c; 
                    if(color[edge[j].u]!=c){ 
                        color[edge[j].u]=c; 
                        dpt[c].push_back(edge[j].u); 
                        node_bcc[edge[j].u].push_back(c); 
                    } 
                    if(color[edge[j].v]!=c){ 
                        color[edge[j].v]=c; 
                        dpt[c].push_back(edge[j].v); 
                        node_bcc[edge[j].v].push_back(c); 
                    } 
                }while(j!=i); 
                //puts("");  
            } 
        } 
        else{ 
            low[u]=min(low[u],dfn[v]); 
            if(dfn[u]>dfn[v]) ss.push(i);   //這句話必須這麼寫!!否則打印點雙聯通內部的邊會出錯  
        } 
    } 

 
int main(){ 
    int n,m,i,j,u,v; 
    scanf("%d %d",&n,&m); 
    init(); 
    for(i=1;i<=m;i++){ 
        scanf("%d %d",&u,&v); 
        addedge(u,v,i,head); 
    } 
    for(i=1;i<=n;i++){ 
        if(!dfn[i]){ 
            tarjan(i,0); 
            cut[i]--;   //對於樹根要減1  
        } 
    } 
    /*printf("%d\n",c);
 
    for(i=1;i<=c;i++){
        for(j=0;j<dpt[i].size();j++) printf("%d ",dpt[i][j]);
        puts("");
    }*/ 
 
    b=c; 
    for(i=1;i<=n;i++) if(cut[i]) color[i]=++c; 
 
    for(i=1;i<=n;i++) 
        for(j=0;j<dpt[i].size();j++){ 
            u=dpt[i][j]; 
            if(cut[u]){ 
                addedge(color[u],i,0,head2); 
            } 
        } 
 
    /*for(i=1;i<=m;i++) printf("%d:%d\n",i,edge_belong[i]);
    for(i=1;i<=n;i++){
        for(j=0;j<node_bcc[i].size();j++) printf("%d ",node_bcc[i][j]);
        puts("");
    }*/ 
    return 0; 

#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>
#define N 2000    //注意縮點後新建的圖的頂點數可能達到2*n-1
#define M 600000  //縮點新建的圖一定是樹
using namespace std;

struct Edge{
    int u,v,id,next;
}edge[M*2];

int head[N],head2[N],cnt;
int dfn[N],low[N],color[N],depth,c,b;   //color數組指示每個割點或者點雙連通分支的在新圖的標號,割點標號均>=c
int cut[N];  //cut不為0表示是割點,分成cut+1塊
stack<int>ss;
vector<int>dpt[N];          //每個點連通分支所包含的節點
vector<int>node_bcc[N];     //每個節點所屬的點連通分支
int edge_belong[N];         //每條邊所屬的點連通分支

void addedge(int u,int v,int id,int * head){
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].id=id;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].u=v;
    edge[cnt].v=u;
    edge[cnt].id=id;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

void init(){
    memset(head,-1,sizeof(head));
    memset(head2,-1,sizeof(head2));
    memset(dfn,0,sizeof(dfn));
    memset(color,0,sizeof(color));
    memset(cut,0,sizeof(cut));
    depth=c=cnt=0;
    for(int i=0;i<N;i++) dpt[i].clear(),node_bcc[i].clear();
    memset(edge_belong,0,sizeof(edge_belong));
}

void tarjan(int u,int fa){
    int i,j;
    dfn[u]=low[u]=++depth;
    for(i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa)continue;
        if(dfn[v]==0){
            ss.push(i);
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v]){
                cut[u]++;
                c++;
                do{
                    j=ss.top();
                    //printf("%d-%d ",edge[j].u,edge[j].v);
                    ss.pop();
                    edge_belong[edge[j].id]=c;
                    if(color[edge[j].u]!=c){
                        color[edge[j].u]=c;
                        dpt[c].push_back(edge[j].u);
                        node_bcc[edge[j].u].push_back(c);
                    }
                    if(color[edge[j].v]!=c){
                        color[edge[j].v]=c;
                        dpt[c].push_back(edge[j].v);
                        node_bcc[edge[j].v].push_back(c);
                    }
                }while(j!=i);
                //puts("");
            }
        }
        else{
            low[u]=min(low[u],dfn[v]);
            if(dfn[u]>dfn[v]) ss.push(i);   //這句話必須這麼寫!!否則打印點雙聯通內部的邊會出錯
        }
    }
}

int main(){
    int n,m,i,j,u,v;
    scanf("%d %d",&n,&m);
    init();
    for(i=1;i<=m;i++){
        scanf("%d %d",&u,&v);
        addedge(u,v,i,head);
    }
    for(i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(i,0);
            cut[i]--;   //對於樹根要減1
        }
    }
    /*printf("%d\n",c);

    for(i=1;i<=c;i++){
        for(j=0;j<dpt[i].size();j++) printf("%d ",dpt[i][j]);
        puts("");
    }*/

    b=c;
    for(i=1;i<=n;i++) if(cut[i]) color[i]=++c;

    for(i=1;i<=n;i++)
        for(j=0;j<dpt[i].size();j++){
            u=dpt[i][j];
            if(cut[u]){
                addedge(color[u],i,0,head2);
            }
        }

    /*for(i=1;i<=m;i++) printf("%d:%d\n",i,edge_belong[i]);
    for(i=1;i<=n;i++){
        for(j=0;j<node_bcc[i].size();j++) printf("%d ",node_bcc[i][j]);
        puts("");
    }*/
    return 0;
}


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved