hdu3749Financial Crisis(点双连通分量)

传送门

题意:如果两个点不在一个连通图中,即无路径相连,输出"zero",如果在同一个连通图中,如果两点路径上必经过割点,输出"one",

其余输出"two or more",点双连通分量(第一次接触,之前都做得有向图缩点)

4/2日更:重新调整状态,重新做了一遍,总算理解并实现了代码。

博客传送门

AC代码:

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10010;
typedef long long ll;
struct edge {
    int f,t, nxt;
}e[maxn << 1];
int hd[maxn], tot;
void add(int f, int t) {
    e[++tot] = { f,t,hd[f] };
    hd[f] = tot;
}
int n, m, q;
int low[maxn], dfn[maxn],lastcol[maxn],in[maxn],cnt,colnum;
vector<int>col[maxn],incol[maxn];
stack<edge>S;
int nowcol;
void init() {
    memset(dfn, 0, sizeof(dfn));
    memset(hd, 0, sizeof(hd));
    memset(lastcol, 0, sizeof(lastcol));
    memset(in, 0, sizeof(in));
    cnt = colnum = nowcol = tot = 0;
    for (int i = 0; i < n; i++) {
        col[i].clear(); incol[i].clear();
    }
}
void dfs(int u, int f) {
    low[u] = dfn[u] = ++cnt;
    in[u] = nowcol;
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (v == f)continue;
        if (!dfn[v]) {
            S.push(e[i]);
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
                edge tmp; colnum++;
                while (1) {
                    tmp = S.top(); S.pop();
                    if (lastcol[tmp.f] != colnum) {
            //由于用的边来表示一个连通分量,一个点可能出现两次,比如1-2,2-3,2就出现了两次,所以需要判重处理,
            //但是这题数据比较水,不加也让A了
                        col[colnum].push_back(tmp.f);//记录这个点连通分量的节点
                        incol[tmp.f].push_back(colnum);//记录这个节点所在的点连通有那些
                        lastcol[tmp.f] = colnum;
                    }
                    if (lastcol[tmp.t] != colnum) {
                        col[colnum].push_back(tmp.t);
                        incol[tmp.t].push_back(colnum);
                        lastcol[tmp.t] = colnum;
                    }
                    if (u == tmp.f && v == tmp.t)break;
                }
            }
        }
        else if (dfn[v] < dfn[u]) {
            S.push(e[i]);
            low[u] = min(low[u], dfn[v]);
        }
    }
}
int main() {
    //freopen("test.txt", "r", stdin);
    int cse = 1;
    while (scanf("%d%d%d", &n, &m, &q) && n) {
        init();
        while (m--) {
            int a, b; scanf("%d%d", &a, &b);
            add(a, b);
            add(b, a);
        }
        for (int i = 0; i < n; i++) {
            if (!dfn[i]) {
                nowcol++;
                dfs(i, -1);
            }
        }
        printf("Case %d:\n", cse++);
        while (q--) {
            int a, b; scanf("%d%d", &a, &b);
            if (in[a] != in[b]) {
                printf("zero\n");
            }
            else {
                int f = 0;
                for (int i = 0; i < incol[a].size()&&!f; i++) {
                    for (int j = 0; j < incol[b].size(); j++) {
                        //如果两点可以出现在同一点连通分量内且有两个以上的点
                        if(incol[a][i]==incol[b][j]&&col[incol[a][i]].size()>2){
                            f = 1; break;
                        }
                    }
                }
                if (f) {
                    printf("two or more\n");
                }
                else {
                    printf("one\n");
                }
            }
        }
    }
    return 0;
}

 

posted @ 2021-03-31 21:55  cono奇犽哒  阅读(49)  评论(0)    收藏  举报