HDU 5876 最短路+补图

3 篇文章 0 订阅
1 篇文章 0 订阅

题目

Sparse Graph

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2225    Accepted Submission(s): 791


Problem Description
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  N1  other vertices.
 

Input
There are multiple test cases. The first line of input is an integer  T(1T<35)  denoting the number of test cases. For each test case, the first line contains two integers  N(2N200000)  and  M(0M20000) . The following  M  lines each contains two distinct integers  u,v(1u,vN)  denoting an edge. And  S (1SN)  is given on the last line.
 

Output
For each of  T  test cases, print a single line consisting of  N1  space separated integers, denoting shortest distances of the remaining  N1  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


题意


  输入的是一个图,但是我们要求的是补图,补图就是整个图减去我们输入的图,这里是百度百科 https://baike.baidu.com/item/%E8%A1%A5%E5%9B%BE?fr=aladdin。


 我先知道了一个点S,求的就是S在这个补图中,到其他个点的最短路,如果不存在就输出-1


解题思路


这个题的关键在于怎么去处理补图,求最短路对我们来说不是什么大问题,那怎么处理补图呢,我们开一个数组link,里面存当前点可以到达的点,再开一个数组inlink存当前点不能到达的点,初始化link的时候把除了自己本身的点我们都加上,无法到达的我们先一个也不存,然后假设我们在起点S,那么根据输入,我们就能找到S无法到达的点,我们把该点从link里面删除,把他加入到inlink,这样子我们计算最短路,只要找link数组就好了,而且这些点到S就是d[s]+1,这里有一个巧妙的计算就是,因为我们是从起点S开始的,如果我们已经找到这个点了我们就不需要再找一次(也就是再加入一次link数组)了,因为他已经是最短路了,需要加入link数组的只有我们还没有找到的点,而我们还没找到的点都在inlink里面,处理完之后交换一下就好了,具体的看代码吧

代码里面用的Set,因为方便插入和删除而且是唯一的,就像图中的点一样每个点也是唯一的。

#include<set>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200000+6;
int n,m;
int d[maxn];
vector<int>e[maxn];
void dfs(int s)
{
    memset(d,0,sizeof(d));
    set<int>link,inlink;
    for(int i=1;i<=n;i++)
    {
        if(i!=s)
            link.insert(i);
    }
    queue<int> q ;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(auto &y:e[x])
        {
            if(!link.count(y))
                continue;
            link.erase(y);
            inlink.insert(y);
        }
        for(auto &y:link)
        {
            d[y]=d[x]+1;
            q.push(y);
        }
        link.swap(inlink);
        inlink.clear();
    }
    int flag=0;
    for(int i=1;i<=n;i++)
    {
        if(i!=s)
        {
            if(flag)
            {
                printf(" ");
            }
            if(!d[i])
                printf("-1");
            else
                printf("%d",d[i]);
            flag=1;
        }
    }
    printf("\n");
}
void work()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        e[i].clear();
    int u,v;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    int s;
    scanf("%d",&s);
    dfs(s);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        work();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值