ZOJ 3232 - It's not Floyd Algorithm(强连通缩点+Floyd)

题目:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3232

题意:

n*n 的矩阵表示图的连通性,求出至少需要多少条边才能实现连通性。

思路:

根据矩阵建图,Cij = 1则建边(i->j)。题目转化为在原有图的基础上删边,使得连通性相同。

对于一个强连通分量中,n个点则需要n条边,而对于一个树来讲,n个点需要n-1条边。

所以先强连通缩点,变成树,对树进行Floyd。

一开始试图用 并查集代替Floyd,但是并查集是没办法处理有向边的情况!!

AC.

#include 
#include 
#include 
#include 
#include 

using namespace std;
const int maxn = 205;
const int maxm = 5e4+4;
int g[maxn][maxn];

struct Edge{
    int to, next;
}edge[maxm];
int head[maxn], tot;
int low[maxn], dfn[maxn], Stack[maxn], belong[maxn];
int Index, top;
int scc;
bool Instack[maxn];
int num[maxn];

void addedge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void tarjan(int u)
{
    int v;
    low[u] = dfn[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for(int i = head[u]; ~i; i = edge[i].next) {
        v = edge[i].to;
        if(!dfn[v]) {
            tarjan(v);
            if(low[u] > low[v]) low[u] = low[v];
        }
        else if(Instack[v] && low[u] > dfn[v]) {
            low[u] = dfn[v];
        }
    }
    if(low[u] == dfn[u]) {
        scc++;
        do {
            v = Stack[--top];
            Instack[v] = false;
            belong[v] = scc;
            num[scc]++;
        }while(v != u);
    }
}
void solve(int N)
{
    memset(dfn, 0, sizeof(dfn));
    memset(Instack, 0, sizeof(Instack));
    memset(num, 0, sizeof(num));
    Index = scc = top = 0;
    for(int i = 1; i <= N; ++i) {
        if(!dfn[i]) tarjan(i);
    }
}

void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
int newg[maxn][maxn];

int main()
{
    //freopen("in", "r", stdin);
    int n;
    while(~scanf("%d", &n)) {
        memset(g, 0, sizeof(g));
        init();
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                scanf("%d", &g[i][j]);
                if(i == j) continue;
                if(g[i][j] == 1) {
                    addedge(i, j);
                }
            }
        }

        solve(n);
        int ans = 0;

        for(int i = 1; i <= scc; ++i) {
            if(num[i] > 1) ans += num[i];
        }

        memset(newg, 0, sizeof(newg));
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                int u = belong[i], v = belong[j];
                if(u != v && g[i][j]) {
                    newg[u][v] = 1;
                }
            }
        }

        for(int k = 1; k <= scc; ++k) {
            for(int i = 1; i <= scc; ++i) {
                for(int j = 1; j <= scc; ++j) {
                    if(newg[i][j] && newg[i][k] && newg[k][j]) {
                        newg[i][j] = 0;
                    }
                }
            }
        }

        for(int i = 1; i <= scc; ++i) {
            for(int j = 1; j <= scc; ++j) {
                if(newg[i][j] == 1) ans++;
            }
        }

        printf("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(强连通分量)