POJ 3694 Network

边双连通分量+并查集

这题算是水过去的吧,4500ms。应该有更好的写法

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 100000 + 10; //结点数量
const int Maxn = 2 * 200000 + 10; //边的数量
int low[maxn];
int dfn[maxn];
int U[Maxn], V[Maxn];//存初始边
int flag[Maxn];//判断第i条边是不是割边
struct Edge
{
    int from, to, id, ans;//ans为1,表示这条边是割边
} edge[Maxn];
vector<int>G[maxn];//邻接表
vector<int>Tree[maxn];//邻接表
int N, M;//N个结点,M条边
int tmpdfn;//时间戳
int tot;
int Start, End;
int TxT[maxn];//求边双连通分量用的

int FF[maxn];
int Cun[maxn];
int Father[maxn];
int MA, Num, Q, X;

void init()
{
    for (int i = 0; i<maxn; i++) G[i].clear();
    for (int i = 0; i<maxn; i++) Tree[i].clear();
    for (int i = 0; i < maxn; i++) Father[i] = i;
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(flag, 0, sizeof(flag));
    memset(TxT, 0, sizeof(TxT));
    memset(FF, 0, sizeof(FF));
    low[1] = dfn[1] = 1;
    tmpdfn = 0;
    tot = 0;
    Num = 0;
}

int Find(int x)
{
    if (x != Father[x]) Father[x] = Find(Father[x]);
    return Father[x];
}

void AddEdge(int u, int v)
{
    edge[tot].from = u;
    edge[tot].to = v;
    edge[tot].id = tot;
    edge[tot].ans = 0;
    G[u].push_back(tot);
    tot++;

    edge[tot].from = v;
    edge[tot].to = u;
    edge[tot].id = tot;
    edge[tot].ans = 0;
    G[v].push_back(tot);
    tot++;
}

int Tarjan(int u, int id)
{
    tmpdfn++;
    int lowu = dfn[u] = tmpdfn;
    for (int i = 0; i<G[u].size(); i++)
    {
        int B = G[u][i];
        if (!dfn[edge[B].to])
        {
            int lowv = Tarjan(edge[B].to, edge[B].id);
            lowu = min(lowu, lowv);
            if (lowv >= dfn[u])
            {
                if (lowv>dfn[u])
                    edge[B].ans = 1;
            }
        }
        else if (dfn[edge[B].to])
        {
            if (edge[B].id / 2 == id / 2) continue;
            lowu = min(lowu, dfn[edge[B].to]);
        }
    }
    low[u] = lowu;
    return lowu;
}

void Dfs(int x, int y)
{
    int XZ = 0;
    for (int i = 0; i<G[x].size(); i++)
    {
        int B = G[x][i];
        if (!flag[edge[B].id / 2])
        {
            XZ = 1;
            flag[edge[B].id / 2] = 1;
            TxT[edge[B].to] = 1;
            int fu = Find(edge[B].from);
            int fv = Find(edge[B].to);
            if (fu != fv) Father[fu] = fv;
            Dfs(edge[B].to, y + 1);
        }
    }
    if (!XZ&&!y) Father[x] = x;
}

void Slove()
{
    for (int i = 0; i<2 * M; i++)
        if (edge[i].ans)
        {
            Num++;
            flag[edge[i].id / 2] = 1;
        }

    for (int i = Start; i <= End; i++)
    {
        if (!TxT[i])
        {
            TxT[i] = 1;
            Dfs(i, 0);
        }
    }
}

int FLAGS;
void DFS(int now, int len, int END)
{
    FF[now] = 1;
    if (now == END)
    {
        MA = len;
        FLAGS = 1;
        return;
    }
    for (int i = 0; i < Tree[now].size(); i++)
    {
        if (!FF[Tree[now][i]])
        {
            int fu = Find(now);
            int fv = Find(Tree[now][i]);
            if (fu == fv)
            {
                DFS(Tree[now][i], len, END);
                if (FLAGS) return;
            }
            else if (fu != fv)
            {
                Cun[len] = Tree[now][i];
                DFS(Tree[now][i], len + 1, END);
                if (FLAGS) return;

            }
        }
    }
}

int main()
{
    int CASE = 1;
    while (~scanf("%d%d", &N, &M))
    {
        if (!N&&!M) break;
        printf("Case %d:\n", CASE);
        CASE++;
        init();
        for (int i = 0; i < M; i++)
        {
            scanf("%d%d", &U[i], &V[i]);
            AddEdge(U[i], V[i]);
        }
        Start = 1;
        End = N;
        Tarjan(1, -1);
        Slove();
        for (int i = 0; i < M; i++)
        {
            int fu = Find(U[i]);
            int fv = Find(V[i]);
            if (fu == fv) continue;
            Tree[fu].push_back(fv);
            Tree[fv].push_back(fu);
        }
        scanf("%d", &Q);
        while (Q--)
        {
            MA = 0;
            FLAGS = 0;
            memset(FF, 0, sizeof FF);
            int u, v;
            scanf("%d%d", &u, &v);
            int fu = Find(u);
            int fv = Find(v);
            if (fu == fv)
            {
                printf("%d\n", Num);
                continue;
            }
            DFS(fu ,0, fv);
            Num = Num - MA;
            for (int i = 0; i < MA; i++)
            {
                int Fa = Find(Cun[i]);
                Father[Fa] = fu;
            }
            printf("%d\n", Num);
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2015-09-01 11:18  Fighting_Heart  阅读(153)  评论(0编辑  收藏  举报