• [BZOJ 1098] [POI2007] 办公楼biu 【链表优化BFS】


    题目链接:BZOJ - 1098

    题目分析

    只有两个点之间有边的时候它们才能在不同的楼内,那么就是说如果两个点之间没有边它们就一定在同一座楼内。

    那么要求的就是求原图的补图的连通块。

    然而原图的补图的边数是 n^2 级别的,非常庞大,我们不能直接把补图求出来。

    可以使用一种用链表优化BFS的做法,开始时将所有的点加到一个链表里。

    每次找一个连通块的时候BFS,在链表中取出一个点,在链表中删除,加入队列,然后每次取出队首元素x,枚举x的每一条边,将边的终点y从链表中删去,加到一个临时的链表中存储。

    这样枚举完 x 的所有边之后,原链表里剩余的点就是与 x 没有边的,这些点在补图里与 x 就是有边的,将这些点加入队列。

    然后用临时的链表替代原链表,原链表中就是剩下的点了。

    这样BFS几次就可以求出所有连通块了。

    每一个点都只被从链表中删去1次,每条边都只遍历了一次,总的时间复杂度是 O(n + m)。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int MaxN = 100000 + 5, MaxM = 2000000 + 5;
    
    inline void Read(int &Num) 
    {
    	char c; c = getchar();
    	while (c < '0' || c > '9') c = getchar();
    	Num = c - '0'; c = getchar();
    	while (c >= '0' && c <= '9') 
    	{
    		Num = Num * 10 + c - '0';
    		c = getchar();
    	}
    }
    
    int n, m, Top, R1, R2, Sum;
    int Ans[MaxN], Last[MaxN], Next[MaxN];
    
    bool InList[MaxN];
    
    struct Edge
    {
    	int v;
    	Edge *Next;
    } E[MaxM * 2], *P = E, *Point[MaxN];
    
    inline void AddEdge(int x, int y) 
    {
    	++P; P -> v = y;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    queue<int> Q;
    
    inline void Add(int x, int y) 
    {
    	Next[y] = Next[x];
    	if (Next[x]) Last[Next[x]] = y;
    	Next[x] = y;
    	Last[y] = x;
    }
    
    inline void Delete(int x) 
    {
    	if (Last[x]) Next[Last[x]] = Next[x];
    	if (Next[x]) Last[Next[x]] = Last[x];
    }
    
    void BFS() 
    {
    	while (!Q.empty()) Q.pop();
    	Q.push(Next[R1]);
    	InList[Next[R1]] = false;
    	Delete(Next[R1]);
    	int x, y;
    	++Top;
    	while (!Q.empty()) 
    	{
    		x = Q.front();
    		++Sum;
    		++Ans[Top];
    		Q.pop(); 
    		R2 = n + 2;
    		Last[R2] = Next[R2] = 0;
    		for (Edge *j = Point[x]; j; j = j -> Next)
    		{
    			y = j -> v;
    			if (!InList[y]) continue;
    			Delete(y);
    			Add(R2, y);
    		}
    		for (int i = Next[R1]; i; i = Next[i]) 
    		{
    			Q.push(i);
    			InList[i] = false;
    		}
    		Next[R1] = Next[R2];
    		Last[Next[R1]] = R1;
    	}
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int a, b;
    	for (int i = 1; i <= m; ++i) 
    	{
    		Read(a); Read(b);
    		AddEdge(a, b);
    		AddEdge(b, a);
    	}
    	Top = 0; Sum = 0;
    	R1 = n + 1;
    	for (int i = 1; i <= n; ++i) Add(R1, i);
    	for (int i = 1; i <= n; ++i) InList[i] = true;
    	while (Sum < n) BFS();
    	printf("%d
    ", Top);
    	sort(Ans + 1, Ans + Top + 1);
    	for (int i = 1; i <= Top; ++i) printf("%d ", Ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    Azure HDInsight 现已在中国正式发布
    避免由于Windows Update自动安装安全补丁导致VM意外重启
    如何修复在Microsoft Azure中“虚拟机防火墙打开,关闭RDP的连接端口”问题
    关于Azure Auto Scale的高级属性配置
    在Azure中使用Load Runner测试TCP最大并发连接数
    Windows Azure案例分析: 选择虚拟机或云服务?
    Windows Server基础架构云参考架构:硬件之上的设计
    浅析基于微软SQL Server 2012 Parallel Data Warehouse的大数据解决方案
    在Windows Azure公有云环境部署企业应用
    如何在后台运行_Linux_命令并且将进程脱离终端
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4322722.html
Copyright © 2020-2023  润新知