您的位置:首页 > 其它

关于图论的一些小结 (二)

2012-10-23 14:59 204 查看
连通分量求法:

强连通分量一定是图的深搜树的一个子树。

对于DAG,两次DFS,第一次DFS原图,第二次DFS反向图

求得各个强连通

DFS一种很文艺的写法

TOJ 2233题

/* 求强连通分量,做法:先对图进行DFS,记录每个节点的结束时间f[i]
* 然后对反图按照f[i]从大到小的顺序对反图进行DFS,在中间过程中记录每个连通分量中最小的值,并将其赋值给其根节点
* 仍然按照上一个顺序DFS累加得到结果
*
*/
#include <cstdio>
#include <cstring>
#include <vector>
#define INF 0x1f1f1f1f
#define M 10002
using namespace std;
vector<int>map[2][M];         //map[0][i]为原图,map[1][i]为反图
int color[M],v[M];          //颜色和花费
int n,depth,money,f[M];                //遍历结束时间
int min(int a,int b){
return a<b?a:b;
}
void dfs(int m,int type){
color[m] = 1;
int i,u;
if(type == 1) money = min(money, v[m]); // 第二次DFS时,记录每个强联通分量中的最小花费
for(i = 0;i < map[type][m].size(); i++){
u = map[type][m][i];
if(color[u] == 0)     //未遍历过
dfs(u,type);
}
if(type == 0)     //在第一次DFS时记录每个节点结束访问的时间
f[depth++] = m;
color[m] = 2;
}
void cal(int m){
color[m] = 1;
int i,u;
for(i = 0;i < map[0][m].size(); i++){
u = map[0][m][i];
if(color[u] == 0) cal(u);
}
}
int main()
{
int i,j,k,m;
while(scanf("%d%d",&n,&m)){
if(m == 0 && n == 0) break;
for(i = 1;i <= n; i++){
scanf("%d",&v[i]);
map[0][i].clear();
map[1][i].clear();
}
while(m--){
scanf("%d%d",&i,&j);
map[0][i].push_back(j);
map[1][j].push_back(i);
}
memset(color,0,sizeof(color));
depth = 0;
for(i = 1;i <= n; i++)
if(!color[i])
dfs(i,0);
memset(color,0,sizeof(color));
for(i = depth-1;i >= 0; i--){
int u = f[i];
money = INF;
dfs(u,1);
v[u] = money;
}
memset(color,0,sizeof(color));
int ans = 0;
for(i = depth-1;i >= 0; i--){
int u = f[i];
if(!color[u]){
cal(u);
ans += v[u];
}
}
printf("%d/n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: