题目链接:HDU 5876
题意:给一个图,求他的补图上的最短路径。
样例:
1
2 0
1
t组数据。第一行给出n, m。n个点、m条边。下面m行给m条无向边。然后给出起点s。
输出按点的顺序输出每个点到起点距离。原点不输出,到不了输出-1。
好久没写bfs了…邻队的思路。
可以把原图以set的形式存到一个邻接表里,然后补图就可以通过判断set里的点来较快的得到边。
这样的话广搜每次扩展都要遍历一遍所有的节点,如若不优化一定超时。考虑每次bfs把所有点存到set里,每次走完的点就从set里删除,这样就不用每次都遍历所有的点了。可以水过。要注意输出格式。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
int n, m, s;
set<int> mp[200010]; //存原图
set<int> book; //存所有没扩展到的点
int ans[200100];
void bfs(int s) {
ans[s] = 0;
queue<int> q;
q.push(s);
int i;
for(i = 1; i <= n; i++) {
if(i != s) book.insert(i); //所有点存入
}
set<int> del; //要删掉的已访问点
while(!q.empty()) {
int now = q.front();
q.pop();
set<int>::iterator it;
del.clear();
for(it = book.begin(); it != book.end(); it++) {
if(!mp[now].count(*it)) {
if(ans[*it] == -1) {
ans[*it] = ans[now] + 1;
del.insert(*it);
q.push(*it);
}
}
}
for(it = del.begin(); it != del.end(); it++) {
book.erase(*it); //删掉已访问点
}
}
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d %d", &n, &m);
int i, j, x, y;
memset(ans, -1, sizeof(ans));
for(i = 0; i <= n; i++) {
mp[i].clear();
}
book.clear();
for(i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
mp[x].insert(y);
mp[y].insert(x);
}
scanf("%d", &s);
bfs(s);
for(i = 1; i <= n; i++) {
if(i == s) continue;
printf("%d", ans[i]);
if(s == n) {
if(i != n - 1) printf(" ");
else printf("\n");
}
else {
if(i != n) printf(" ");
else printf("\n");
}
}
}
return 0;
}