2016大连网络赛Sparse Graph

本文分享了一道关于补图的BFS算法题目的解题思路及AC代码,通过逆向思维简化问题,并讨论了使用set维护未访问节点的技巧,避免了不必要的复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

唉,比赛时首先想到了bfs,没想太多直接交一发超时,然后开始用set建领结表,set维护未被访问的点优化,结果无限mlt,挂了5小时机,最后还是由队友打掉了这题。。。
其实,这题很好想,逆着想想,就是补图的bfs题,赛后才发现自己为何mlt,手贱加了个vis数组标记访问(其实不需要,set已维护了未访问点,自己还加了个set<int>pos中间值,并不知道自己当时在干嘛- -)真是手贱啊!!!!
今天看了一波题解,思想一致,一看代码,卧槽!!!这特么跟我的太像了!!!(只怪自己太菜。。。
给出之后的ac代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<stack>
#include<queue>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#define mem(a,b) memset(a,b,sizeof(a))
#define memmax(a) memset(a,0x3f,sizeof(a))
#define pfn printf("\n")
#define ll __int64
#define mod 1000000007
#define sf(a) scanf("%d",&a)
#define sf64(a) scanf("%I64d",&a)
#define sf264(a,b) scanf("%I64d%I64d",&a,&b)
#define sf364(a,b,c) scanf("%I64d%I64d%I64d",&a,&b,&c)
#define sf2(a,b) scanf("%d%d",&a,&b)
#define sf3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sf4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define sff(a) scanf("%f",&a)
#define sfs(a) scanf("%s",a)
#define sfs2(a,b) scanf("%s%s",a,b)
#define sfs3(a,b,c) scanf("%s%s%s",a,b,c)
#define sfc(a) scanf("%c",&a)
#define debug printf("***\n")
const double PI = acos(-1.0);
const double e = exp(1.0);
const int INF = 0x7fffffff;;
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
bool cmpbig(int a, int b){ return a>b; }
bool cmpsmall(int a, int b){ return a<b; }
using namespace std;
#define MAX 200010
set<int>maps[MAX], a,c;
int  path[MAX];
int main()
{
	freopen("data.in", "r", stdin);
	int t;
	sf(t);
	while (t--)
	{
		mem(path, -1);
		int i, m, n;
		sf2(n, m);
		a.clear();
		for (i = 1; i <= n; i++)
		{
			maps[i].clear();
			a.insert(i);
		}
		for (i = 0; i < m; i++)
		{
			int u, v;
			sf2(u, v);
			maps[u].insert(v);
			maps[v].insert(u);
		}
		int s;
		sf(s);
		a.erase(s);
		path[s] = 0;
		queue<int>q;
//		a.erase(s);
		q.push(s);
		while (!q.empty())
		{
			c.clear();
			int now_pos = q.front();
			q.pop();
			for (set<int>::iterator it = a.begin(); it != a.end(); it++)
			{
				int pos = *it;
				if (maps[pos].find(now_pos) == maps[pos].end())
				{
					path[pos] = path[now_pos] + 1;
					c.insert(pos);
					q.push(pos);
				}
			}
			for (set<int>::iterator it = c.begin(); it != c.end(); it++)
				a.erase(*it);
		}
		int flag = 0;
		for (i = 1; i <= n; i++)
		{
			if (i != s)
				flag ? printf(" %d", path[i]),flag++ : printf("%d", path[i]),flag++;
		}
		pfn;
	}
	return 0;
}
可能有人会问,为何还加个c集合,直接循环里删a集合中的点不就可以了。这是因为it迭代器在不断的往后移位,而如果你在循环中a.erase()某个值,则it位置会不知何处,编译器会报错!(这确实是看了网上某苣代码 学到的新东西- -)
唉 ,,总结还是自己太菜。。
# 导入需要的模块 import numpy as np import open3d as o3d # 用于读写pcd文件 from sklearn.neighbors import kneighbors_graph # 用于构建KNN图 from scipy.sparse.csgraph import connected_components # 用于找到连通域 # 读取点云数据 pc = o3d.io.read_point_cloud(r'E:\BISHE\pcd\neuvsnap_0418_154523.pcd') # 读取pcd文件 points = np.asarray(pc.points) # 转换为numpy数组 # 构建KNN图,k为邻居数,可以根据数据密度调整 k = 10 graph = kneighbors_graph(points, k, mode='connectivity', include_self=False) # 找到最大的连通域 n_components, labels = connected_components(graph, directed=False) largest_label = np.argmax(np.bincount(labels)) # 找到点数最多的标签 largest_component = points[labels == largest_label] # 筛选出对应的点 # 保存筛选后的点云数据为pcd文件 pc_filtered = o3d.geometry.PointCloud() # 创建新的点云对象 pc_filtered.points = o3d.utility.Vector3dVector(largest_component) # 设置点云数据 o3d.io.write_point_cloud(r'E:\BISHE\pcd\output1.pcd', pc_filtered) # 保存为pcd文件 # 为点云数据设置颜色 colors = np.zeros((points.shape[0], 3)) # 创建一个颜色数组,大小和点云数组一致 colors[labels == largest_label] = [0.5, 0.5, 0.5] # 将保留的点云设置为灰色 colors[labels != largest_label] = [1.0, 0.0, 0.0] # 将处理的点云设置为红色 pc.colors = o3d.utility.Vector3dVector(colors) # 将颜色数组赋值给点云对象 # 可视化点云数据 o3d.visualization.draw_geometries([pc]) # 调用open3d的可视化函数,显示点云对象这段代码降噪原理是什么
05-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值