Sparse Graph HDU - 5876(求补图最短路BFS)

Sparse Graph HDU - 5876

In graph theory, the complement of a graph G is a graph H on the same vertices such that two distinct vertices of H are adjacent if and only if they are not adjacent in G.

Now you are given an undirected graph G of N nodes and M bidirectional edges of unit length. Consider the complement of G, i.e., H. For a given vertex S on H, you are required to compute the shortest distances from S to all N−1
other vertices.
Input
There are multiple test cases. The first line of input is an integer T(1≤T<35) denoting the number of test cases. For each test case, the first line contains two integers N(2≤N≤200000) and M(0≤M≤20000). The following M lines each contains two distinct integers u,v(1≤u,v≤N) denoting an edge. And S (1≤S≤N)
is given on the last line.
Output
For each of T test cases, print a single line consisting of N−1 space separated integers, denoting shortest distances of the remaining N−1 vertices from S
(if a vertex cannot be reached from S, output “-1” (without quotes) instead) in ascending order of vertex number.
Sample Input

1
2 0
1

Sample Output

1
题意:

给一个图,和起点s,求s在补图中各个点的最短路

分析:

可以把原图以set的形式存到一个邻接表里,然后补图就可以通过判断set里的点来较快的得到边。
这样的话广搜每次扩展都要遍历一遍所有的节点,如若不优化一定超时。考虑每次bfs把所有点存到set里,每次走完的点就从set里删除,这样就不用每次都遍历所有的点了。可以水过。要注意输出格式

code:

#include <bits/stdc++.h>
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);//将除s外的点存入作为待访问的点表示还没到达
    }
    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;//距离为到达当前点的距离+1
                    del.insert(*it);//此时说明我们到达了这点,加入队列
                    q.push(*it);//并将到达的新点加入删除set中以后不用再看这个点了
                }
            }
        }
        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(int i = 0; i <= n; i++){
            mp[i].clear();
        }
        book.clear();
        for(int i = 0; i < m; i++){//存图
            scanf("%d%d",&x,&y);
            mp[x].insert(y);
            mp[y].insert(x);
        }
        scanf("%d",&s);
        bfs(s);
        for(int i = 1; i <= n; i++){
            if(i == s) continue;
            printf("%d",ans[i]);
            if(s == n){
                if(i != n - 1) putchar(' ');
                else putchar('\n');
            }
            else{
                if(i != n) putchar(' ');
                else putchar('\n');
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值