zoj3232_It's not Floyd Algorithm(tarjan縮點/floyd)

題目大意

給一張有向圖,求最少能用多少有向邊建圖使新圖的連通性和原圖相同。

思路

在圖中不存在環的情況下,當兩點間能間接到達時,可將兩點間的直接邊刪去,可用floyd求最長路,當兩點間的距離爲1時,則兩點間不能間接到達,只能建邊。

可用tarjan縮點將有環圖轉爲DAG,在縮點後的圖上跑floyd即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
#define INF 0x3f3f3f3f
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 210
using namespace std;
int g[MAXN][MAXN], fld[MAXN][MAXN], d[MAXN][MAXN], n;
int dfn[MAXN], low[MAXN];///dfn[]表示深搜的步數,low[u]表示u或u的子樹能夠追溯到的最早的棧中節點的次序號
int sccno[MAXN];///縮點數組,表示某個點對應的縮點值
int step;
int scc_cnt;///強連通分量個數

vector<int> scc[MAXN];///得出來的縮點,scc[i]裏面存i這個縮點具體縮了哪些點
stack<int> S;
void dfs(int u)
{
    dfn[u] = low[u] = ++step;
    S.push(u);
    for (int i = 1; i <= n; i++)
    {
        if (i == u || !g[u][i])
            continue;
        int v = i;

        if (!dfn[v])
        {
            dfs(v);
            low[u] = min(low[u], low[v]);
        }
        else if (!sccno[v])
            low[u] = min(low[u], dfn[v]);

    }

    if (low[u] == dfn[u])
    {
        scc_cnt += 1;
        scc[scc_cnt].clear();

        while(1)
        {
            int x = S.top();
            S.pop();

            if (sccno[x] != scc_cnt) scc[scc_cnt].push_back(x);
            sccno[x] = scc_cnt;
            if (x == u) break;

        }

    }

}

void tarjan(int n)
{
    memset(sccno, 0, sizeof(sccno));
    memset(dfn, 0, sizeof(dfn));

    while (!S.empty())
        S.pop();
    for (int i = 0; i < MAXN; i++)
        scc[i].clear();
    step = scc_cnt = 0;

    for (int i = 1; i <=n; i++)
        if (!dfn[i]) dfs(i);

}

void floyd()
{
    for (int k = 1; k <= scc_cnt; k++)
    {
        for (int i = 1; i <= scc_cnt; i++)
        {
            if (i == k)
                continue;
            for (int j = 1; j <= scc_cnt; j++)
            {
                if (i == j || j == k)
                    continue;

                if (fld[i][k] && fld[k][j])
                    fld[i][j] = MAX(fld[i][k] + fld[k][j], fld[i][j]);


            }
        }
    }
    int ans = 0;
    for (int i = 1; i <= scc_cnt; i++)
    {
        for (int j = 1; j <= scc_cnt; j++)
        {
            if (i == j)
                continue;
            if (fld[i][j] == 1)
                ans++;
        }

    }
  
    for (int i = 1; i <= scc_cnt; i++)
        if (scc[i].size() > 1)
            ans += scc[i].size();
    printf("%d\n", ans);

  

}


int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE

    while (scanf("%d", &n) != EOF)
    {

        mem(g, 0);
        mem(fld, 0);
        mem(d, 0);

        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                scanf("%d", &g[i][j]);
        tarjan(n);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (g[i][j])
                    fld[sccno[i]][sccno[j]] = 1;
            }
        }
        floyd();



    }





    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章