题目链接:https://cn.vjudge.net/problem/HDU-5876
题目大意
n个点,m条边,现在把原图中没有直接相连的点连起来,求起点到各个点的最短路。
分析
把原图中没有直接相连的点连起来,这不就是完全图的补图吗,但n最大是2e5,我们不可能把原先没连起来的边抽出来新建一个图。那换个思路,广搜,用两个set,s1,s2,s1保存没有和当前点相连的,并且没有更新过的点,s2保存与当前点相连的点,假设走到一个点x,那么寻找与x相连的点(向前星),在s1中剔除,放到s2内,找完之后,把s1中的点的距离更新,那么剩下的没有更新过的点就在s2中,令s1等于s2,s2清空,反复更新,这样每个点只更新一次,减少了时间复杂度。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
const int N = 2e5+10;
int n, m, s, cnt;
int head[2*N], dis[N];
struct node{
int pos, d;
node(){}
node(int pos, int d)
{
this->pos = pos;
this->d = d;
}
};
struct Edge{
int to, nxt;
}edge[2*N];
void add(int a, int b)
{
edge[cnt].to = b;
edge[cnt].nxt = head[a];
head[a] = cnt++;
}
void bfs()
{
memset(dis, 0, sizeof dis);
set<int> s1, s2;//s1:没有与当前点相连的,s2:与当前点相连的
set<int>::iterator it;
for(int i = 1; i <= n; i++)
{
if(i != s)
s1.insert(i);
}
queue<node> q;
q.push(node(s, 0));
while(!q.empty())
{
node tmp = q.front();
q.pop();
dis[tmp.pos] = tmp.d;
for(int i = head[tmp.pos]; i != -1; i = edge[i].nxt)
{
int j = edge[i].to;
if(!s1.count(j)) continue;
s1.erase(j);
s2.insert(j);
}
for(it = s1.begin(); it != s1.end(); it++)
q.push(node(*it, tmp.d + 1));
s1 = s2;
s2.clear();
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
cnt = 0;
memset(head, -1, sizeof head);
scanf("%d %d", &n, &m);
while(m--)
{
int a, b;
scanf("%d %d", &a, &b);
add(a, b);
add(b, a);
}
scanf("%d", &s);
bfs();
int num = 1;
for(int i = 1; i <= n; i++)
{
if(i == s) continue;
printf("%d", dis[i] == 0 ? -1 : dis[i]);
printf("%s", num == n - 1 ? "\n" : " ");
num++;
}
}
return 0;
}