您的位置:首页 > 编程语言 > Go语言

zoj 3232 It's not Floyd Algorithm(强联通分量,缩点)

2014-01-24 21:56 411 查看
题目

/******************************************************************/

以下题解来自互联网:Juny的博客

思路核心:给你的闭包其实就是一个有向图;
方法:

1,对此图进行缩点,对于点数为n(n>1)的强连通分量最少要 n 条边,

对点数为 1 的强连通不需要边,这样计算出边数 m1 ;
2,在缩点后的有向无环图中进行反floyd,如果有边a->b,b->c,a->c那么显然a->c可以去掉,

就这样一直去除这样的边,直到不能再去为止,算出最终边数 m2;
3,m1+m2 即为答案;

这样做速度比较慢,但小草还没想出其他好的办法,希望有大牛指点……

/*****************************************************************/

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define MAXN 20010
#define MAXM 50010

struct Edge
{
int v, next;
}edge[MAXM];    //边结点数组

int first[MAXN], stack[MAXN], DFN[MAXN], Low[MAXN], Belong[MAXM];
// first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,
//Belong[]为每个结点所对应的强连通分量标号数组
// Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号
int instack[MAXM],num[MAXN];  // instack[]为是否在栈中的标记数组
int n, m, cnt, scnt, top, tot;

void init()
{
cnt = 0;
scnt = top = tot = 0;
memset(first, -1, sizeof(first));
memset(DFN, 0, sizeof(DFN));
memset(num,0,sizeof(num));
}

void read_graph(int u, int v)
{
edge[tot].v = v;
edge[tot].next = first[u];
first[u] = tot++;
}

void Tarjan(int v)
{
int  t;
DFN[v] = Low[v] = ++cnt;
instack[v] = 1;
stack[top++] = v;
for(int e = first[v]; e != -1; e = edge[e].next)
{
int j = edge[e].v;
if(!DFN[j])
{
Tarjan(j);
if(Low[v] > Low[j]) Low[v] = Low[j];

}
else if(instack[j] && DFN[j] < Low[v])
{
Low[v] = DFN[j];
}
}
if(DFN[v] == Low[v])
{
scnt++;
do
{
t = stack[--top];
instack[t] = 0;
Belong[t] = scnt;  //为缩点做准备的
num[scnt]++;
}while(t != v);
}
}

void solve()
{
for(int i = 1; i <= n; i++)
if(!DFN[i])
Tarjan(i);
}

int main()
{
int i,j,map[210][210],sum1,ans,map1[210][210];//map1[][]是缩点后新建的图
while(scanf("%d",&n)!=EOF)
{
init();
ans=0;
memset(map,0,sizeof(map));
memset(map1,0,sizeof(map1));
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j]==1&&i!=j)
{
read_graph(i,j);
}
}
}
solve();
sum1=0;
for(i=1;i<=scnt;i++)
{
if(num[i]>1)
sum1+=num[i];
}
for(int ii=1;ii<=n;ii++)
{
for(int jj=1;jj<=n;jj++)
{
if(map[ii][jj]&&Belong[ii]!=Belong[jj])
map1[Belong[ii]][Belong[jj]]=1;
}
}
for(int ii=1;ii<=scnt;ii++)
for(int jj=1;jj<=scnt;jj++)
for(int kk=1;kk<=scnt;kk++)
if(map1[ii][jj]&&map1[ii][kk]&&map1[kk][jj])//此处在缩点新建图
map1[ii][jj]=0;
for(int ii=1;ii<=scnt;ii++)
for(int jj=1;jj<=scnt;jj++)
if(map1[ii][jj])
ans++;
printf("%d\n",sum1+ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: