图的遍历(洛谷)

  • p2661 信息传递

这道题实际上就是求图的最小环,这里用并查集的方法实现。

#include <cstdio>
#include <algorithm>
using namespace std ;
const int N = 2e5 + 5 ; 
int s[N] , h[N] ;
int ans = N ; 
int find(int x){
	if (x != s[x]){
		int t = s[x] ;	//记录父节点 
		s[x] = find(s[x]) ;	//更新为祖先节点 
		h[x] += h[t] ; 
		//h[x]是x相对于父节点的长度,h[t]是x的父节点相对于祖先节点的长度,合起来就是x相对于祖先节点的长度,且x已经更新为祖先节点了 
	}
	return s[x] ; 
}
void built(int x , int y){
	int a = find(x) ;
	int b = find(y) ; 
	if (a != b){
		s[a] = b ;
		h[x] = h[y] + 1 ;
	}else{
		ans = min(ans,h[x]+h[y]+1) ; //祖先节点相同则可以成环(环的长度为两个节点到祖先节点的长度+1) 
	}
}
int main(){
	int n ; 
	scanf ("%d",&n) ;
	for (int i = 1 ; i <= n ; ++ i){
		s[i] = i ; 
		h[i] = 0 ; 
	} 
	for (int i = 1 ; i <= n ; ++ i){
		int x ; 
		scanf ("%d",&x) ;
		built(i,x) ; 
	}
	printf ("%d\n",ans) ; 
	return 0 ; 
}
  • p1330 封锁阳光

题意是每个点要分隔开但是取走的点不能相邻,转化为染色就是相邻的点不能为同种颜色。
做法:遍历未染色的点,将未染色的点染为黑色,相邻的点染为白色,依次类推,要注意每次dfs是当前的联通图,取断点要去当前的最小值,所以在开始遍历那里之前,颜色数量要清0。

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std ; 
const int N = 1e4 + 5 ; 
int n , m ; 
int vis[N] , color[2] ; 
vector<int> r[N] ; 
int ans ; 
int dfs(int i){
	for (int j = 0 ; j < r[i].size() ; ++ j){
		int t = r[i][j] ; 
		if (vis[t] == -1){
			vis[t] = (vis[i]+1)%2 ; 
			color[vis[t]] ++ ;	
			dfs(t) ; 
		}
		else{
			if (vis[i] == vis[t]){	//新的颜色和旧的颜色相同(冲突)
				printf ("Impossible\n") ;
				exit(0) ; //退出程序  
			}
		}
	}
	return min(color[0],color[1]+1) ; 
}
int main(){
	scanf ("%d%d",&n,&m) ;
	memset(vis,-1,sizeof(vis)) ; 
	while(m--){	//建图 
		int v , u ; 
		scanf ("%d%d",&v,&u) ; 
		r[v].push_back(u) ; 
		r[u].push_back(v) ; 
	}
	for (int i = 1 ; i <= n ; ++ i){
		if (r[i].size() == 0)	continue ;  //为单独的点不用搜索
		color[0] = 0 , color[1] = 0 ;	//注意清0,因为每次要返回当前连通图染色数最少的点 
		if (vis[i] == -1){	//未上色
			vis[i] = 1 ; 
			ans += dfs(i) ; 
		}
	}
	printf ("%d\n",ans) ;
	return 0 ; 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值