Kosaraju算法有些不懂

emailed 2008-05-01 09:40:13
算法如下:
1。先dfs一遍整个图 , 回溯后记录每个点.
2。然后把记录的点到着再dfs(有点象stack后进先出).
3。第2次dfs时把有向图的边全部反向。
4。每找一次他们就是一个块的。。。。


假如说现在有4个点
1 2(表示1到2有一条有向边)
2 1
2 3
4

第一步:遍历一遍该图(假设从1开始遍历),则遍历顺序为1,2,3,4
第三步:反向
然后,从4开始遍历,然后是3。。。。。

这时,本来没有3到2那条边的,将图反向后就有了这条边阿,这么一来不就是产生了两个强连通分量吗?
第一个(4),第二个(1,2,3)

但是观察得答案是三个强连通分量(4),(3),(1,2)

不知道怎么回事啊??还有我觉得这两遍的dfs没有什么关系啊??

麻烦哪位大牛指点一下吧


...全文
684 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
tailzhou 2008-05-04
  • 打赏
  • 举报
回复
若图有边,从一个分量指向另一分量,被指向的分量不需要通知;

因为通知指向它的另一分量的任意点都可以通知到该分量;
emailed 2008-05-04
  • 打赏
  • 举报
回复
恩,对阿,道理都明白了,就是不知道代码应该怎么写啊 。。。。
emailed 2008-05-04
  • 打赏
  • 举报
回复
终于自己搞定了,唉。。。
emailed 2008-05-03
  • 打赏
  • 举报
回复
哪位大哥教教吧
tailzhou 2008-05-02
  • 打赏
  • 举报
回复
对于不止一个节点的强连通分量,也有可能不需要通知其中任一节点的;

因为可能有别的连通分量指向他;

应该是将连通分量退化成一个节点,如果该退化节点的入度为0,就通知该连通分量的费用最小的一个节点;

medie2005 2008-05-02
  • 打赏
  • 举报
回复
acm最好自己做,做不出了就看解题报告,看不懂了就问同学,同学不会了就问老师,老师不会了就baidu,baidu没有了就骂baidu.
tailzhou 2008-05-02
  • 打赏
  • 举报
回复
谁告诉你这个题是求有向图的强连通分量的?

根本就不是.



tailzhou 2008-05-02
  • 打赏
  • 举报
回复
"然后把记录的点到着再dfs(有点象stack后进先出). "

栈的状态依次为:
1
1 2
1 2 3
1 2
1
4

其出栈的顺序的 3 2 1 4;
所以第二次的顺序是 4; 1, 2; 3;
tailzhou 2008-05-02
  • 打赏
  • 举报
回复
第一次遍历的访问次序是1,2,3,4;
但第一次遍历的访问完成时间顺序是 3,2,1,4;

第二次遍历是按照"访问完成时间"从后向前的顺序的;
所以第二次是先从4开始;然后是1,2;最后是3;
emailed 2008-05-02
  • 打赏
  • 举报
回复
不是阿,这个题求有向图的强连通分量(Kosaraju算法),对于求出的每个强连通分量,如果该分量的点只有一个,则如果该点入度为0,则将通知它的费用加进去;
对于多于一个点的强连通分量,只需通知其中最小费用的点;


但是我肯定是有点地方的实现没注意到阿
tailzhou 2008-05-02
  • 打赏
  • 举报
回复
这个题不是求连通分量呀;

emailed 2008-05-02
  • 打赏
  • 举报
回复
没格式重贴一次:


#include<iostream>
using namespace std;
struct Node
{
int num;
Node* next;
};
const int MAXN=10000;
Node node1[MAXN+1],node2[MAXN+1];//两个邻接表,一个正向,一个逆向
int visit[MAXN+1];
int degree[MAXN+1];//记录每个点的入度
int order[MAXN+1];//记录dfs过程结束访问点的顺序
int part[MAXN+1];//记录哪个点属于哪个强连通分量,比如part[i]==ans,则点i属于第ans个强连通分量
int mincost[MAXN+1];//记录每个强连通分量中花费最小的点
int cost[MAXN+1];//记录每个点的花费
int cnt[MAXN+1];//记录每个强连通分量中有几个点,比如cnt[i]==j,则第i个强连通分量有j个点

int ans;
int t;

void DFS1(int i)
{
if(visit[i]==1)
return ;
visit[i]=1;
Node* p=node1[i].next;
while(p)
{
DFS1(p->num);
p=p->next;
}
order[++t]=i;
}
void DFS2(int i)
{
if(visit[i]==1)
return ;
visit[i]=1;
Node* p=node2[i].next;
while(p)
{
DFS2(p->num);
p=p->next;
}
part[i]=ans;
cnt[ans]++;
if(cost[i]<mincost[ans])
mincost[ans]=cost[i];

}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
memset(visit,0,sizeof(visit));
memset(part,0,sizeof(part));
memset(degree,0,sizeof(degree));
memset(node1,0,sizeof(node1));
memset(node2,0,sizeof(node2));
memset(cnt,0,sizeof(cnt));
int i,j;
for(i=1;i<=n;i++)
mincost[i]=10010;
for(i=1;i<=n;i++)
{
node1[i].next=NULL;
node2[i].next=NULL;
}
for(i=1;i<=n;i++)
cin>>cost[i];
Node* p;
for(i=1;i<=m;i++)
{
p=new Node;
int s,t;
cin>>s>>t;
degree[t]++;
p->num=t;
p->next=node1[s].next;
node1[s].next=p;
p=new Node;

p->num=s;
p->next=node2[t].next;
node2[t].next=p;
}
t=0;
for(i=1;i<=n;i++)
{
if(!visit[i])
DFS1(i);

}
memset(visit,0,sizeof(visit));
ans=0;
for(i=n;i>=1;i--)
{
if(!visit[order[i]])
{
ans++;
DFS2(order[i]);
}

}
int tot=0;
for(i=1;i<=ans;i++)
{
if(cnt[i]==1)
{
for(j=1;j<=n;j++)
{
if(part[j]==i)
break;
}
if(degree[j]==0)
tot+=cost[j];

}
else
{
tot+=mincost[i];
}
}
cout<<tot<<endl;
}
return 0;
}













emailed 2008-05-02
  • 打赏
  • 举报
回复
我晕阿,一点都没有错啊,很多数据都测试过了,还是wa阿

原题链接:http://acm.tju.edu.cn/toj/showp2233.html
就是个Kosaraju算法

我的代码如下:死活找不到错啊,帮忙看看吧


#include<iostream>
using namespace std;
struct Node
{
int num;
Node* next;
};
const int MAXN=10000;
Node node1[MAXN+1],node2[MAXN+1];//两个邻接表,一个正向,一个逆向
int visit[MAXN+1];
int degree[MAXN+1];//记录每个点的入度
int order[MAXN+1];//记录dfs过程结束访问点的顺序
int part[MAXN+1];//记录哪个点属于哪个强连通分量,比如part[i]==ans,则点i属于第ans个强连通分量
int mincost[MAXN+1];//记录每个强连通分量中花费最小的点
int cost[MAXN+1];//记录每个点的花费
int cnt[MAXN+1];//记录每个强连通分量中有几个点,比如cnt[i]==j,则第i个强连通分量有j个点

int ans;
int t;

void DFS1(int i)
{
if(visit[i]==1)
return ;
visit[i]=1;
Node* p=node1[i].next;
while(p)
{
DFS1(p->num);
p=p->next;
}
order[++t]=i;
}
void DFS2(int i)
{
if(visit[i]==1)
return ;
visit[i]=1;
Node* p=node2[i].next;
while(p)
{
DFS2(p->num);
p=p->next;
}
part[i]=ans;
cnt[ans]++;
if(cost[i]<mincost[ans])
mincost[ans]=cost[i];

}
int main()
{
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
memset(visit,0,sizeof(visit));
memset(part,0,sizeof(part));
memset(degree,0,sizeof(degree));
memset(node1,0,sizeof(node1));
memset(node2,0,sizeof(node2));
memset(cnt,0,sizeof(cnt));
int i,j;
for(i=1;i<=n;i++)
mincost[i]=10010;
for(i=1;i<=n;i++)
{
node1[i].next=NULL;
node2[i].next=NULL;
}
for(i=1;i<=n;i++)
cin>>cost[i];
Node* p;
for(i=1;i<=m;i++)
{
p=new Node;
int s,t;
cin>>s>>t;
degree[t]++;
p->num=t;
p->next=node1[s].next;
node1[s].next=p;
p=new Node;

p->num=s;
p->next=node2[t].next;
node2[t].next=p;
}
t=0;
for(i=1;i<=n;i++)
{
if(!visit[i])
DFS1(i);

}
memset(visit,0,sizeof(visit));
ans=0;
for(i=n;i>=1;i--)
{
if(!visit[order[i]])
{
ans++;
DFS2(order[i]);
}

}
int tot=0;
for(i=1;i<=ans;i++)
{
if(cnt[i]==1)
{
for(j=1;j<=n;j++)
{
if(part[j]==i)
break;
}
if(degree[j]==0)
tot+=cost[j];

}
else
{
tot+=mincost[i];
}
}
cout<<tot<<endl;
}
return 0;
}












emailed 2008-05-02
  • 打赏
  • 举报
回复
to tailzhou:
那这个所谓的“缩点”应该怎么去实现呢??
emailed 2008-05-02
  • 打赏
  • 举报
回复
嗯,是9楼的那意思,忽略了这一点

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧