MYF

HDU 5876 Sparse Graph

题目链接

HDU 5876

题目类型:补图的最短路

题目来源:2016 ACM/ICPC Asia Regional Dalian Online

题目分析

题目大意

给出一张图,问对于指定起点该图的补图中起点到每一个点的距离。其中补图的定义为,将原图中的所有边都去掉,原图中两点之间如果不存在边则添加这条边,存在边则不添加,形成的图

解析

很容易想到是BFS,如果原图中和起点相连,那它们两者之间的距离必然不是1,如果两者之间没有边直接相连,那么补图中两者之间的距离就是1,然后我们对于每次新加入进来的点进行BFS,但是问题是,点的数量很大,如果暴力的去扫肯定会T掉,在这里灵活的运用了set这种数据结构,一开始先存储所有未加入补图的点,对于每一个队首元素,可以将未加入补图的点分为两部分,一部分是可以直接加入补图,也就是说在原图中和队首元素不相连的点,一部分是不能直接加入补图,也就是说在原图中和队首元素相邻的点。每次将新加入补图的点入队,然后重复执行这个过程,就可以保证到每一个点的距离都是最小的。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <bitset>
#include <cstring>
#include <iostream>
#include <iosfwd>
#include <deque>
#include <algorithm>
#define Memset(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)
#define PB push_back
#define MP make_pair
#define rt(n) (i == n ? '\n' : ' ')
#define hi printf("Hi----------\n")
#define IN freopen("input.txt","r",stdin);
#define OUT freopen("output.txt","w",stdout);
#define debug(x) cout<<"Debug : ---"<<x<<"---"<<endl;
#define debug2(x,y) cout<<"Debug : ---"<<x<<" , "<<y<<"---"<<endl;
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int maxn=200000+5;
const int mod=1000000007;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
vector<int> G[maxn],ans;
int dis[maxn];
void bfs(int s,int n){
memset(dis, INF, sizeof(dis));
queue<int>q;
set<int> ta,tb; //未访问结合 以及 当前情况下不可访问集合
for (int i = 1; i<=n; i++) {
if (i!=s) {
ta.insert(i);
}
}

dis[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();

// 将未访问的点分为当前情况下可以访问的点ta以及当前情况下不可访问的点
for (int i = 0; i<G[u].size(); i++) {
int v = G[u][i];
if (ta.find(v)==ta.end()) continue; //已经访问过
ta.erase(v);
tb.insert(v);
}

// 更新当前情况下可以访问的点的距离
for (set<int>::iterator it = ta.begin(); it!=ta.end(); it++) {
dis[*it] = dis[u] + 1;
q.push(*it);
}
ta.swap(tb);
tb.clear();
}
}
void work(){
int n,m,s;
scanf("%d%d",&n,&m);

for (int i = 1; i<=n; i++) G[i].clear();

for (int i = 1; i<=m; i++) {
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
scanf("%d",&s);

bfs(s, n);

ans.clear();
for (int i = 1; i<=n; i++) {
if (i==s)
continue;
if (dis[i] == INF)
ans.push_back(-1);
else
ans.push_back(dis[i]);
}

for (int i = 0 ; i<ans.size(); i++) {
printf("%d%c",ans[i]," \n"[i==ans.size()-1]);
}
}
int main(){
int T;
while (scanf("%d",&T)!=EOF) {
while (T--) {
work();
}
}
}