题意:
有n个点的无向完全图,有m条边的边权为1,其余都为0,求最小生成树的权值。
思路:
初始时,生成树的大小为0,先把点1加入进去,然后把那种不需要花费权值,就可以加入的点,先加入进去,
因为每加入一些点,就会有一些点,从需要花费权值 转变为 不需要花费权值,所以要优先加入这样的点。
怎么判断这个点加入需不需要花费权值,
每次加入一个点的时候,就把与这个点相连的点加1,如果这个点的值,等于生成树的大小,那么就说明它与生成树中所有的点都相连,所以它需要花费权值。
如果未在生成树中的所有点的值,都等于生成树大小了,那就随便加入一个点,那就很可能会再解锁一些点。
就这样循环搞,直到所有点都加入生成树了为止。
用队列实现。
这样的复杂度不好算,于是,假设最糟糕的情况(或许有更糟糕的,但是我想不到了)
有1000个点,1e6条边的权值都为1(题目的m最大才1e5,不过没关系,稍微糟糕一点)
那么就意味着,每次遍历完点都没有发现可以无花费就加入的点,那也就n2 级别的复杂度,可以过。
(为什么这样的题我要写这么多字啊。。。)
代码
#include <stdio.h> #include <string.h> #include <iostream> #include <cmath> #include <vector> #include <queue> using namespace std; typedef long long ll; const int maxn = 1e5 + 10; vector<int>mp[maxn]; int qu[maxn*10]; int n,m,num[maxn]; int main(){ while(scanf("%d%d",&n,&m) != EOF){ int u,v,now = 0; for(int i = 1;i <= n;i++) mp[i].clear(); memset(num,0,sizeof(num)); for(int i = 1;i <= m;i++){ scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u); } now = 1; for(int i = 0;i < mp[1].size();i++){ v = mp[1][i]; num[v] = 1; } int ans = 0,l = 0,r = 0,_l,_r,flag; for(int i = 2;i <= n;i++) qu[r++] = i; flag = 0; while(l < r){ _r = r; flag = 0; while(l < _r){ u = qu[l++]; if(num[u] < now){ flag = 1; now++; for(int j = 0;j < mp[u].size();j++){ v = mp[u][j]; num[v]++; } } else{ qu[r++] = u; } } if(!flag){ ans++; now++; u = qu[l++]; for(int i = 0;i < mp[u].size();i++){ v = mp[u][i]; num[v]++; } } } printf("%d ",ans); } return 0; }