zoukankan      html  css  js  c++  java
  • luogu P3452 [POI2007]BIU-Offices

    两种写法,主要是复杂度的证明上比较有趣
    1. 并查集+BFS
    对于每个点,最多只会进入队列一次,这部分的复杂度是O(n)
    每个点最多会在 for (int i = find(1); i <= n; i = find(i + 1))这段话中被访问 (edge[i].size() + 1) 次,因为如果某个点和它没有边,这个点就会和后面的合并,再也不会在这个循环中被访问到,而和它有边的点只有 edge[i].size() 个,所以在edge[i].size() + 1 次时一定可以把它合并,因此 (Sigma{edge[i].size()}=m),这部分最多被访问 (O(m)) 次,因此总的复杂度为 (O(n + m))

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 10;
    vector < int > edge[N];
    int ans[N], f[N], n, m, cnt, vis[N];
    int find(int x) {
    	return f[x] == x ? x : f[x] = find(f[x]);
    }
    void BFS(int x) {
    	queue < int > q;
    	q.push(x); f[x] = x + 1;
    	ans[++cnt] = 1;
    	while (!q.empty()) {
    		int u = q.front(); q.pop();
    		for (auto v:edge[u])
    			vis[v] = u;
    		for (int i = find(1); i <= n; i = find(i + 1))
    			if (vis[i] != u)
    				q.push(i), ans[cnt]++;
    	}     
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= m; i++) {
    		int a, b;
    			scanf("%d%d", &a, &b);
    			edge[a].push_back(b);
    			edge[b].push_back(a);
    		}
    	for (int i = 1; i <= n + 1; i++)	f[i] = i;
    	for (int i = 1; i <= n; i++)
    		if (f[i] == i)
    			BFS(i);
    	printf("%d
    ", cnt);
    	sort(ans + 1, ans + cnt + 1);
    	for (int i = 1; i <= cnt; i++)
    		printf("%d ", ans[i]);
    	return 0;
    }
    
    1. 链表+队列
      大概的想法和上面差不多,唯一的区别就是把删除的过程变成了并查集的合并变成了链表的删除。
  • 相关阅读:
    如何查看python的notebook文件.ipynb
    pip3与pyttsx3文字语音转换
    Python字符乱码
    python3的urllib以及urllib2的报错问题
    python人脸对比
    Python 爬取qqmusic音乐url并批量下载
    稳定排序和不稳定排序
    Linux信号、信号处理和信号处理函数
    jQuery ajax表单提交
    Django setting 常用配置
  • 原文地址:https://www.cnblogs.com/cminus/p/14932660.html
Copyright © 2011-2022 走看看