网赛的时候没做出来,后来看题解懂的。
首先将所有节点都放进集合a,表示未求出最短距离。
由于以S为起点,所以dis[S]=0,从集合中将其删除,扔进队列。
每次跑队列的时候,取出首元素u,将集合a遍历一边,如果集合中的元素x与其没有边相连(用set存边,这样可以较快判断),那么dis[x]=dis[u]+1。并将其扔进队列,从集合中删除它。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <set>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=2e5+5;
set<int> E[MAXN];
int dis[MAXN];
int main(int argc, char const *argv[])
{
int t;
scanf("%d",&t);
while(t--){
int n,m,S;
scanf("%d %d",&n,&m);
set<int> a;
for(int i=1;i<=n;i++) E[i].clear(),a.insert(i);
while(m--){
int u,v;
scanf("%d %d",&u,&v);
E[u].insert(v);
E[v].insert(u);
}
scanf("%d",&S);
a.erase(S);
msc(dis);
dis[S]=0;
queue<int> q;
q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
set<int> b;
for (set<int>::iterator i = a.begin(); i != a.end(); ++i)
if(E[u].find(*i)==E[u].end()){
dis[*i]=dis[u]+1;
b.insert(*i);
q.push(*i);
}
for (set<int>::iterator i = b.begin(); i != b.end(); ++i)
a.erase(*i);
}
for(int i=1;i<=n;i++)
if(dis[i]) printf("%d%c",dis[i],i==n?'\n':' ' );
}
return 0;
}