【专题】图的连通性问题

来源:互联网 发布:磁力链接搜索引擎源码 编辑:程序博客网 时间:2024/04/29 18:57


有向图的强连通分量

POJ 1236 - Network of Schools(基础)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1236
题意:问添加多少边可成为完全连通图
解法:缩点,看度数


/** head-file **/#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <vector>#include <queue>#include <stack>#include <list>#include <set>#include <map>#include <algorithm>/** define-for **/#define REP(i, n) for (int i=0;i<int(n);++i)#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)#define REP_1(i, n) for (int i=1;i<=int(n);++i)#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)#define REP_N(i, n) for (i=0;i<int(n);++i)#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)#define REP_1_N(i, n) for (i=1;i<=int(n);++i)#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)/** define-useful **/#define clr(x,a) memset(x,a,sizeof(x))#define sz(x) int(x.size())#define see(x) cerr<<#x<<" "<<x<<endl#define se(x) cerr<<" "<<x/** test **/#define Display(A, n, m) {                      \    REP(i, n){                                  \        REP(j, m) cout << A[i][j] << " ";       \        cout << endl;                           \    }                                           \}#define Display_1(A, n, m) {                    \    REP_1(i, n){                                \        REP_1(j, m) cout << A[i][j] << " ";     \        cout << endl;                           \    }                                           \}using namespace std;/** typedef **/typedef long long LL;/** Add - On **/const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };const int MOD = 1000000007;const int INF = 0x3f3f3f3f;const long long INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;const int maxn=111111;const int maxm=511111;int n,m;struct EDGENODE{    int to;    int w;    int next;};struct SGRAPH{    int head[maxn];    EDGENODE edges[maxm];    int edge;    void init()    {        clr(head,-1);        edge=0;    }    void addedge(int u,int v,int c=1)    {        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;    }    int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;    stack<int>stk;    void dfs(int u)    {        pre[u]=lowlink[u]=++dfs_clock;        stk.push(u);        for (int i=head[u];i!=-1;i=edges[i].next){            int v=edges[i].to;            if (!pre[v]){                dfs(v);                lowlink[u]=min(lowlink[u],lowlink[v]);            } else if (!sccno[v]){                lowlink[u]=min(lowlink[u],pre[v]);            }        }        if (lowlink[u]==pre[u]){            scc_cnt++;            int x;            do{                x=stk.top();                stk.pop();                sccno[x]=scc_cnt;            }while (x!=u);        }    }    void find_scc(int n)    {        dfs_clock=scc_cnt=0;        clr(sccno,0);        clr(pre,0);        while (!stk.empty()) stk.pop();        REP_1(i,n) if (!pre[i]) dfs(i);    }};SGRAPH solver;bool mp[111][111];int main(){    int ans1,ans2;    int idd,odd;    while (~scanf("%d",&n))    {        clr(mp,0);        solver.init();        REP_1(i,n)        {            int xt;            while (~scanf("%d",&xt))            {                if (xt==0) break;                solver.addedge(i,xt);            }        }        solver.find_scc(n);        REP(u,n)        {            for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)            {                int v=solver.edges[i].to;                if (solver.sccno[u]!=solver.sccno[v])                {                    mp[solver.sccno[u]][solver.sccno[v]]=true;                }            }        }        //Display_1(mp,solver.scc_cnt,solver.scc_cnt);        ans1=ans2=0;        m=solver.scc_cnt;        REP_1(i,m)        {            idd=0;            odd=0;            REP_1(j,m)            {                if (mp[j][i]) idd++;                if (mp[i][j]) odd++;            }            if (!idd) ans1++;            if (!odd) ans2++;        }        ans2=max(ans1,ans2);        if (m==1) ans2=0;        printf("%d\n%d\n",ans1,ans2);    }    return 0;}

POJ 2553 - The Bottom of a Graph(基础)

找出度为零的强连通分量,把符合条件的点都输出出来。

/** head-file **/#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <vector>#include <queue>#include <stack>#include <list>#include <set>#include <map>#include <algorithm>/** define-for **/#define REP(i, n) for (int i=0;i<int(n);++i)#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)#define REP_1(i, n) for (int i=1;i<=int(n);++i)#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)#define REP_N(i, n) for (i=0;i<int(n);++i)#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)#define REP_1_N(i, n) for (i=1;i<=int(n);++i)#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)/** define-useful **/#define clr(x,a) memset(x,a,sizeof(x))#define sz(x) int(x.size())#define see(x) cerr<<#x<<" "<<x<<endl#define se(x) cerr<<" "<<x#define pb push_back#define mp make_pair/** test **/#define Display(A, n, m) {                      \    REP(i, n){                                  \        REP(j, m) cout << A[i][j] << " ";       \        cout << endl;                           \    }                                           \}#define Display_1(A, n, m) {                    \    REP_1(i, n){                                \        REP_1(j, m) cout << A[i][j] << " ";     \        cout << endl;                           \    }                                           \}using namespace std;/** typedef **/typedef long long LL;/** Add - On **/const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };const int MOD = 1000000007;const int INF = 0x3f3f3f3f;const long long INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;const int maxn=111111;const int maxm=511111;int n,m;struct EDGENODE{    int to;    int w;    int next;};struct SGRAPH{    int head[maxn];    EDGENODE edges[maxm];    int edge;    void init()    {        clr(head,-1);        edge=0;    }    void addedge(int u,int v,int c=0)    {        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;    }    int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;    stack<int>stk;    void dfs(int u)    {        pre[u]=lowlink[u]=++dfs_clock;        stk.push(u);        for (int i=head[u];i!=-1;i=edges[i].next){            int v=edges[i].to;            if (!pre[v]){                dfs(v);                lowlink[u]=min(lowlink[u],lowlink[v]);            } else if (!sccno[v]){                lowlink[u]=min(lowlink[u],pre[v]);            }        }        if (lowlink[u]==pre[u]){            scc_cnt++;            int x;            do{                x=stk.top();                stk.pop();                sccno[x]=scc_cnt;            }while (x!=u);        }    }    void find_scc(int n)    {        dfs_clock=scc_cnt=0;        clr(sccno,0);        clr(pre,0);        while (!stk.empty()) stk.pop();        REP_1(i,n) if (!pre[i]) dfs(i);    }}solver;bool a[5555][5555];vector<int>ans;vector<int>ot;int main(){    while (~scanf("%d",&n))    {        if (n==0) break;        scanf("%d",&m);        clr(a,0);        solver.init();        while (m--)        {            int x,y;            scanf("%d%d",&x,&y);            solver.addedge(x,y);        }        solver.find_scc(n);        m=solver.scc_cnt;        REP_1(u,n)        {            for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)            {                int v=solver.edges[i].to;                if (solver.sccno[u]!=solver.sccno[v])                {                    a[solver.sccno[u]][solver.sccno[v]]=true;                }            }        }        ans.clear();        REP_1(i,m)        {            int sum=0;            REP_1(j,m)            {                if (a[i][j]) sum++;            }            if (sum==0) ans.push_back(i);        }        ot.clear();        REP(k,sz(ans))        REP_1(i,n)        if (solver.sccno[i]==ans[k]) ot.push_back(i);        sort(ot.begin(),ot.end());        REP(i,sz(ot)-1)        {            cout<<ot[i]<<" ";        }        cout<<ot[sz(ot)-1]<<endl;    }    return 0;}

POJ 2762 - Going from u to v or from v to u?(中等)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2762
题意:单向连通图判定
解法:缩点 + dp找最长链

/** head-file **/#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <vector>#include <queue>#include <stack>#include <list>#include <set>#include <map>#include <algorithm>/** define-for **/#define REP(i, n) for (int i=0;i<int(n);++i)#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)#define REP_1(i, n) for (int i=1;i<=int(n);++i)#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)#define REP_N(i, n) for (i=0;i<int(n);++i)#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)#define REP_1_N(i, n) for (i=1;i<=int(n);++i)#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)/** define-useful **/#define clr(x,a) memset(x,a,sizeof(x))#define sz(x) int(x.size())#define see(x) cerr<<#x<<" "<<x<<endl#define se(x) cerr<<" "<<x#define pb push_back#define mp make_pair/** test **/#define Display(A, n, m) {                      \    REP(i, n){                                  \        REP(j, m) cout << A[i][j] << " ";       \        cout << endl;                           \    }                                           \}#define Display_1(A, n, m) {                    \    REP_1(i, n){                                \        REP_1(j, m) cout << A[i][j] << " ";     \        cout << endl;                           \    }                                           \}using namespace std;/** typedef **/typedef long long LL;/** Add - On **/const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };const int MOD = 1000000007;const int INF = 0x3f3f3f3f;const long long INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;const int maxn=1111;const int maxm=11111;int n,m;struct EDGENODE{    int to;    int w;    int next;};struct SGRAPH{    int head[maxn];    EDGENODE edges[maxm];    int edge;    void init()    {        clr(head,-1);        edge=0;    }    void addedge(int u,int v,int c=0)    {        edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;    }    int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;    stack<int>stk;    void dfs(int u)    {        pre[u]=lowlink[u]=++dfs_clock;        stk.push(u);        for (int i=head[u];i!=-1;i=edges[i].next){            int v=edges[i].to;            if (!pre[v]){                dfs(v);                lowlink[u]=min(lowlink[u],lowlink[v]);            } else if (!sccno[v]){                lowlink[u]=min(lowlink[u],pre[v]);            }        }        if (lowlink[u]==pre[u]){            scc_cnt++;            int x;            do{                x=stk.top();                stk.pop();                sccno[x]=scc_cnt;            }while (x!=u);        }    }    void find_scc(int n)    {        dfs_clock=scc_cnt=0;        clr(sccno,0);        clr(pre,0);        while (!stk.empty()) stk.pop();        REP_1(i,n) if (!pre[i]) dfs(i);    }}solver;bool a[maxn][maxn];bool topsort(){    int idd[maxn];    int cnt=0;    queue<int>que;    clr(idd,0);    REP_1(i,m)    {        REP_1(j,m)        {            if (a[j][i]) idd[i]++;        }        if (idd[i]==0) que.push(i);    }    if (que.size()>1) return false;    while (!que.empty())    {        int u=que.front();        que.pop();        cnt=0;        REP_1(v,m)        {            if (a[u][v])            {                idd[v]--;                if (idd[v]==0) {que.push(v);cnt++;};            }        }        if (cnt>1) return false;    }    return true;}int main(){    int T;    scanf("%d",&T);    while (T--)    {        scanf("%d%d",&n,&m);        solver.init();        REP(i,m)        {            int x,y;            scanf("%d%d",&x,&y);            solver.addedge(x,y);        }        solver.find_scc(n);        m=solver.scc_cnt;        clr(a,0);        REP_1(u,n)        {            for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)            {                int v=solver.edges[i].to;                if (solver.sccno[u]==solver.sccno[v]) continue;                a[solver.sccno[u]][solver.sccno[v]]=true;            }        }        if (topsort()) puts("Yes");        else puts("No");    }    return 0;}



无向图的双连通分量

POJ 3352 - Road Construction(中等)

http://acm.pku.edu.cn/JudgeOnline/problem?id=3352
题意:添加多少条边可成为双向连通图
解法:把割边分开的不同分量缩点构树,看入度
建议对比下1236,有向图添加多少条边变成强连通图

/** head-file **/#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <vector>#include <queue>#include <stack>#include <list>#include <set>#include <map>#include <algorithm>/** define-for **/#define REP(i, n) for (int i=0;i<int(n);++i)#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)#define REP_1(i, n) for (int i=1;i<=int(n);++i)#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)#define REP_N(i, n) for (i=0;i<int(n);++i)#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)#define REP_1_N(i, n) for (i=1;i<=int(n);++i)#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)/** define-useful **/#define clr(x,a) memset(x,a,sizeof(x))#define sz(x) int(x.size())#define see(x) cerr<<#x<<" "<<x<<endl#define se(x) cerr<<" "<<x#define pb push_back#define mp make_pair/** test **/#define Display(A, n, m) {                      \    REP(i, n){                                  \        REP(j, m) cout << A[i][j] << " ";       \        cout << endl;                           \    }                                           \}#define Display_1(A, n, m) {                    \    REP_1(i, n){                                \        REP_1(j, m) cout << A[i][j] << " ";     \        cout << endl;                           \    }                                           \}using namespace std;/** typedef **/typedef long long LL;/** Add - On **/const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };const int MOD = 1000000007;const int INF = 0x3f3f3f3f;const long long INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;const int maxn=1111;const int maxm=5111;int n,m;struct EDGENODE{    int to;    int w;    bool cut;    int next;};struct SEDGE{    int u;    int v;    SEDGE(int uu=0,int vv=0){u=uu;v=vv;}};struct BCC_GRAPH{    int head[maxn];    EDGENODE edges[maxm];    int edge;    void init()    {        clr(head,-1);        edge=0;    }    void addedge(int u,int v,int c=0)    {        edges[edge].cut=0,edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;    }    //BCC_Tarjan    int dfn[maxn],low[maxn],bccno[maxn],dfs_clock,bcc_cnt;    bool iscut[maxn];    vector<int>bcc[maxn];    stack<SEDGE>stk;    int dfs(int u,int fa)    {        int lowu=dfn[u]=++dfs_clock;        int child=0;        for (int i=head[u];i!=-1;i=edges[i].next)        {            int v=edges[i].to;            if (v==fa) continue;            SEDGE e=SEDGE(u,v);            if (!dfn[v])            {                stk.push(e);                child++;                int lowv=dfs(v,u);                lowu=min(lowu,lowv);                if (dfn[u]<=lowv) //cut 割点                {                    iscut[u]=true;                    //done 点双连通                    bcc_cnt++;                    bcc[bcc_cnt].clear();                    SEDGE x;                    do{                        x=stk.top();                        stk.pop();                        if (bccno[x.u]!=bcc_cnt)                        {                            bcc[bcc_cnt].push_back(x.u);                            bccno[x.u]=bcc_cnt;                        }                        if (bccno[x.v]!=bcc_cnt)                        {                            bcc[bcc_cnt].push_back(x.v);                            bccno[x.v]=bcc_cnt;                        }                    }while (x.u!=u||x.v!=v);                    //over                }                if (dfn[u]<lowv)  //cut 桥                {                    edges[i].cut=true;                    edges[i^1].cut=true;                }            }            else if (dfn[v]<dfn[u])            {                stk.push(e);//done                lowu=min(lowu,dfn[v]);            }        }        if (fa<0&&child==1) iscut[u]=0;        low[u]=lowu;        return lowu;    }    void find_bcc(int n)    {        while (!stk.empty()) stk.pop();        clr(dfn,0);        clr(iscut,0);        clr(bccno,0);        dfs_clock=bcc_cnt=0;        REP_1(i,n)        {            if (!dfn[i]) dfs(i,-1);        }    }    //another    int block[maxn];    int vis[maxn];    int b_num;    void b_dfs(int u)    {        vis[u]=true;        block[u]=b_num;        for (int i=head[u];i!=-1;i=edges[i].next)        {            if (edges[i].cut) continue;            int v=edges[i].to;            if (!vis[v]) b_dfs(v);        }    }    void find_block(int n)    {        //find_block 边双连通        clr(block,0);        clr(vis,0);        b_num=0;        REP_1(i,n)        {            if (!vis[i])            {                b_num++;                b_dfs(i);            }        }    }}solver;bool a[maxn][maxn];int main(){    while (~scanf("%d%d",&n,&m))    {        clr(a,0);        solver.init();        REP(i,m)        {            int x,y;            scanf("%d%d",&x,&y);            solver.addedge(x,y);            solver.addedge(y,x);        }        solver.find_bcc(n);        solver.find_block(n);        REP_1(u,n)        {            for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)            {                int v=solver.edges[i].to;                if ( solver.block[u]!=solver.block[v] )                {                    a[ solver.block[u] ][ solver.block[v] ]=true;                    a[ solver.block[v] ][ solver.block[u] ]=true;                }            }        }        int ans=0;        REP_1(i,solver.b_num)        {            int tmp=0;            REP_1(j,solver.b_num)            {                if (a[i][j]) tmp++;            }            if (tmp==1) ans++;        }        //Display_1(a,solver.b_num,solver.b_num);        ans=(ans+1)/2;        printf("%d\n",ans);    }    return 0;}



原创粉丝点击