环和链的判断

Hand in Hand  HDU - 3926 

 

给一一副有单环的图 判断是否同构

我们可以判断环有多少个,链有多少个,同时判断一下每个环的点数和链的点的个数

第一种做法:

所以,我们可以直接用并查集来做.

同时,我们注意到两幅图的人数应该是一样的.

所以,把并查集修改一下就直接判断了. (如果成环,最后成环的并集会让点的个数加倍.  同时,因为人数是固定的,所以可以直接sort,然后比较)

#include <bits/stdc++.h>

using namespace std;

int fa[10050];
int id1[10050], id2[10050]; 
int find(int idx) { return fa[idx] < 0 ? idx : fa[idx] = find(fa[idx]); }

inline void Union(int x, int y) {
    int xf = find(x);
    int yf = find(y);
    if (fa[xf] > fa[yf]) swap(xf, yf);
    fa[xf] = fa[xf] + fa[yf];
    if (xf == yf) return ;  // 注意 放到这个位置的意义,就是为了判环.
    fa[yf] = xf;
}

int main()
{
    int t, n, m, i, v, u, cnt1, cnt2;
    scanf("%d", &t);
    for (int cas=1; cas<=t; ++cas) {
        memset(fa, -1, sizeof(fa));    
        scanf("%d%d",&n, &m);
        for (i=1; i<=m; ++i) {
            scanf("%d%d", &u, &v);
            Union(u, v);
        }
        cnt1 = cnt2 = 0;
        for (i=1; i<=n; ++i) 
            if (fa[i]<0) id1[cnt1++] = abs(fa[i]);
        memset(fa, -1, sizeof(fa));    
        scanf("%d%d", &n, &m);
        for (i=1; i<=m; ++i) {
            scanf("%d%d", &u, &v);
            Union(u, v);
        }
        for (i=1; i<=n; ++i) 
            if (fa[i]<0) id2[cnt2++] = abs(fa[i]);
        printf("Case #%d: ", cas);
        if (cnt1 != cnt2) {
            printf("NO\n");
            continue;
        }
        sort(id1, id1+cnt1);
        sort(id2, id2+cnt2);
        for (i=0; i<cnt1; ++i) 
            if (id1[i] != id2[i]) break;
        if (i==cnt1) printf("YES\n");
        else printf("NO\n");
    }
    
    return 0;
}
View Code

 

第二种做法:

我们注意到别个点的度数都只有2.所以我们Tarjan可以根据点的个数和度数来判环.

用Tarjan求连通分量, 同时将每个环和链的点数分别求出.

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct Edge {
    int lst;
    int to;
};

class TARJAN {
public:
    Edge edge[20500];
    int n, m;
    int head[10500]; int qsz;
    
    int  dfn[10500]; 
    int  dfn_num;  
    int  low[10500];     
    
    int inSt[10500];    
    int st[10500]; int top; 
    
    int cir[10500];
    int line[10500];
    int in[10500];
    int cir_cnt, line_cnt;
    
    void init() {
        qsz = 1;
        cir_cnt = line_cnt = 0;
        dfn_num = top = 0;
        memset(head, 0, sizeof(head));
        memset(dfn, 0, sizeof(dfn));
        memset(in, 0, sizeof(in));
    }
    
    inline void add(int u, int v) {
        edge[qsz].lst = head[u];
        edge[qsz].to  = v;
        head[u] = qsz++;    
    }
    
    void build() {
        int i, u, v;
        scanf("%d%d", &n, &m);
        for (i=1; i<=m; ++i) {
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
            in[u]++;
            in[v]++;
        }
    }
    
    void Tarjan(int u) {
        int v, i;
        dfn[u] = low[u] = ++dfn_num;
        st[++top] = u;    
        inSt[u] = true;     
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;        
            if (!dfn[v]) {
                Tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (inSt[v]) {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u]) { 
            int cnt_node = 0;
            int cnt_in   = 0;
            do {
                inSt[st[top]] = false;
                cnt_node++;
                cnt_in += in[st[top]];
            } while (st[top--] != u);
            if (cnt_node*2 == cnt_in) // 这个题度数都只有2  所以如果节点数乘以2等于所有点入度,那么就成环. 
                cir[cir_cnt++]   = cnt_node;
            else 
                line[line_cnt++] = cnt_node;
        }
    }
    
    void _get() {
        init();
        build();
        for (int i=1; i<=n; ++i) 
            if (!dfn[i]) 
                Tarjan(i);
    }
}t1, t2;



int main()
{
    int t, n, m, u, v, i, cas;
    scanf("%d", &t);
    for (cas=1; cas<=t; cas++) {
        t1._get();  t2._get();

        printf("Case #%d: ", cas);
        if (t1.cir_cnt!=t2.cir_cnt || t1.line_cnt!=t2.line_cnt) {
            printf("NO\n");
            continue;
        }
        sort(t1.cir, t1.cir+t1.cir_cnt);
        sort(t2.cir, t2.cir+t2.cir_cnt);
        bool flag = true;
        for (i=0; i<t1.cir_cnt; ++i) {
            if (t1.cir[i] != t2.cir[i]) {
                flag = false;
                break;
            }
        }
        if (flag) {
        sort(t1.line, t1.line+t1.line_cnt);
        sort(t2.line, t2.line+t2.line_cnt);
            for (i=0; i<t1.line_cnt; ++i) {
                if (t1.line[i] != t2.line[i]) {
                    flag = false;
                    break;
                }
            }
        }

        if (flag) printf("YES\n");
        else printf("NO\n");
    }
    
    
    return 0;
}
View Code

 

posted @ 2018-09-01 21:48  过路人1998  阅读(457)  评论(0编辑  收藏  举报