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

连通分量求法:

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

对于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);
	}
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值