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;
}

 

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