题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5876
题意:求补图上起点到所有其它点的最短距离
对每一个点,我们只用更新原图不邻接且没有访问过的点既可,复炸度O(m + n)
代码:
#include <bits/stdc++.h>
#define sf scanf
#define pf printf
using namespace std;
const int maxn = 200000 + 5,maxm = 20000 + 5;
struct Edge{
int v,pre;
}Es[maxm * 2];
int head[maxn];
int tot;
void INIT_EDGE(){
tot = 0;
memset(head,-1,sizeof head);
}
void ADD_EDGE(int u,int v){
Es[tot].v = v;
Es[tot].pre = head[u];
head[u] = tot++;
}
int dis[maxn];
void BFS(int s,int n){
set<int> s1,s2;
queue<int> Q;
set<int>::iterator it;
dis[s] = 0;
for(int i = 1;i <= n;++i) if(i != s) s1.insert(i);
Q.push(s);
while( !Q.empty() ){
int cur = Q.front();Q.pop();
for(int i = head[cur];~i;i = Es[i].pre){
int v = Es[i].v;
if(!s1.count(v)) continue; //节点V已经访问过
s1.erase(v); //从未访问节点中删除v
s2.insert(v); //补图中 cur节点不能访问的未访问节点
}
for(it = s1.begin();it != s1.end();++it){
Q.push(*it);
dis[*it] = dis[cur] + 1;
}
s1.swap(s2);
s2.clear();
}
}
void INIT(){
INIT_EDGE();
memset(dis,-1,sizeof dis);
}
int main(){
int T,n,m,u,v,s;
sf("%d",&T);
while( T-- ){
INIT();
sf("%d%d",&n,&m);
for(int i = 0;i < m;++i){
sf("%d%d",&u,&v);ADD_EDGE(u,v);ADD_EDGE(v,u);
}
sf("%d",&s);
BFS(s,n);
for(int i = 1;i <= n;++i)
if(i != s) pf("%d%c",dis[i],i == n ? '\n' : ' ');
}
return 0;
}