题意:给你一个图,有n个节点,m条边,如果两个节点之间有边,则边权值为1,否则这两个节点之间的边权值为0。求这个图的最小生成树的边权值的和。
思路:求这个图的逆向图的联通块的个数,答案就是个数减1,因为n个联通块只需要n-1条线段就可以变成一个联通块,而对于每个联通块来说,任意两点的边权都是0,可以默认看成一棵树。如何求出联通块的个数,用一个set-s保存每个节点的编号,set-G【u】保存与u节点有边的节点的编号,bfs这个节点,如果s中的节点与u节点没有边相连接,那么把这个节点保存到队列中,标记这个节点,具体看代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
set<int>s,G[maxn];
int vis[maxn];
queue<int>q;
void bfs(int u)
{
vis[u]=1;
s.erase(u);
q.push(u);
while(!q.empty())
{
int x=q.front();
q.pop();
set<int>::iterator it;
for(it=s.begin();it!=s.end();)
{
int v=*it;
++it;
if(G[x].find(v)==G[x].end())
{
vis[v]=1;
s.erase(v);
q.push(v);
}
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
s.insert(i);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].insert(v);
G[v].insert(u);
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
bfs(i);
++ans;
}
}
cout<<ans-1<<'\n';
}