题目:http://acm.hdu.edu.cn/showproblem.php?pid=5876
题意:
给你n个点,m条无向边,让你求其无向完全图的补图的单源最短路。
分析:
第一反应是把补图找出来,然后跑一下单源最短路就行了~~
然而补图并不容易找,仔细想想,在原图上直接跑最短路是可行的,扩展结点的时候,把还没访问的点并且与当前点不连接的点就是与当前结点再补图中相连的点,并且是最短路。
实现的话,用两个set维护一下就行。
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int>pii;
const double PI = acos (-1.0);
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 9;
int n, m, d[N];
struct Edge {
int v, next;
} edge[N];
int head[N], tot;
void addedge (int u, int v) {
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void bfs (int s) {
queue<int>q;
q.push (s);
d[s] = 0;
set<int>s1, s2;
for (int i = 1; i <= n; i++) if (i != s) s1.insert (i);
while (!q.empty() ) {
int u = q.front();
q.pop();
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v;
if (!s1.count (v) ) continue;
s1.erase (v);
s2.insert (v);
}
for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
d[*it] = d[u] + 1;
q.push (*it);
}
s1.swap (s2);
s2.clear();
}
}
int main() {
//freopen ("f.txt", "r", stdin);
int u, v;
int T;
scanf ("%d", &T);
while (T--) {
scanf ("%d%d", &n, &m);
memset (head, -1, sizeof (head) );
tot = 0;
for (int i = 0; i < m; i++) {
scanf ("%d%d", &u, &v);
addedge (u, v);
addedge (v, u);
}
scanf ("%d", &u);
bfs (u);
bool flag = 0;
for (int i = 1; i <= n; i++) {
if (i == u) continue;
if (flag) putchar (' ');
flag = 1;
if (d[i] == INF) printf ("-1");
else printf ("%d", d[i]);
}
printf ("\n");
}
return 0;
}