大连acm hdu 5876 补图

题目:http://hdu.hustoj.com/showproblem.php?pid=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 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
 


Sample Output
1
 


Source
 
 
 
 
题意:  给你1样例
            给你n个点和m条边
            输入m条边后
            输入起点s
 
      求原图的补图中,,起点s到各个点的最短距离并输出   
     补图 ;   一个n个点的图有n*(n-1)*0.5条边,,,除去原图上的边剩下的所有边组成补图
  
概念如图 ;
  
                                                            
 
 
好了题意清楚了,,其实刚开始想法很简单,,不就是补图嘛,,通过原来的图把补图还原出来,直接迪杰就ok
 
但是复杂度过高,优化是不可能的,,所以又找到了一种做法  因为只会出现3种答案吧(-1,,1,,2)
 
从起点找起,,把和起点没有联系的点用队列存起来,如图就是存4和5    更新dis[4]和dis[5]=1     从队列中取出4和5 分别为起点  找没有联系的点3和2   更新队列和dis[3],,dis[2]=dis[4]+1;
 
好了方法已经找到了,,写出来了也,,但是还是超时 ,,想半天原来红色区域的查找复杂度也有n*(n-x)*(n-x)....显然超时
 
怎么办呢,,想到了set维护,,set能跟快速的管理和查找删除 所需要的元素  所以代码就出来了  因为对于set的维护还不熟悉只能看别人的代码,,实力太弱
 
对着网上写的代码:后面会补上自己的代码
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
#include<map>
#define maxn 200005
using namespace std;
int n,m,s;
int x,y;
set<int>book;//存所有没扩展到的点
set<int>mp[maxn]; //存原图
int ans[maxn];    // 最短距离
void bfs(int s)
{
    ans[s]=0;
    queue<int>que;
    que.push(s);   //把起点存入队列
    for(int i=1;i<=n;i++)
    {
        if(i!=s)book.insert(i);  //所有点先存入
    }
    set<int>del;  //存要删除的已访问的点
    while(!que.empty())
    {
        int now=que.front();
        que.pop();
        set<int>::iterator it;
        del.clear();  //清空所有元素
        for(it=book.begin();it!=book.end();it++)    //查找与now没有连接的点 可以说是这题的难点所在
        {
            if(!mp[now].count(*it))  //返回mp[now]的元素个数
            {
                if(ans[*it]==-1)
                {
                    ans[*it]=ans[now]+1;
                    del.insert(*it);
                    que.push(*it);
                }
            }
        }
        for(it=del.begin();it!=del.end();it++)
        {
            book.erase(*it);  //删除book里的已经访问元素
        }
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        memset(ans,-1,sizeof(ans));  //初始化ans数组
        for(int i=0;i<=n;i++)
        {
            mp[i].clear();   //清空mp
        }
        book.clear(); //清空book
        for(int i=0;i<m;i++)
        {
            cin>>x>>y;
            mp[x].insert(y);
            mp[y].insert(x);   //双向存点
        }
        cin>>s;
        bfs(s);
        //  以下是输出格式
        for(int i=1;i<=n;i++)
        {
            if(s==i)continue;
            cout<<ans[i];
            if(s==n)
            {
                if(i!=n-1)printf(" ");
                else cout<<endl;
            }
            else
            {
                if(i!=n)cout<<" ";
                else cout<<endl;
            }
        }
    }
    return 0;
}

思路并不复杂,,就是想要维护操作的时候想不到

原文地址:https://www.cnblogs.com/huangzzz/p/8666415.html