hdu 5876(bfs+STL)

5 篇文章 0 订阅

题意 : 现在给你一个图 一个起点,你要求出该点到原图的补图上所有点的最短距离。

思路: 一开始把点分为1 组(与S没有边 的点, 既 一步能够走到的点 )和2组(和S有边的点 既从 S一步走不到的点) 两组点,然后很想当然的认为 只需要考虑1组对2组的影响,如果二组中有一个点使得 并不是1中所有的点都与他有边 ,那么这个点一定是在2步到达,然后考虑2组对 2组的影响,只要2组中有一个点使得 并不是其他所有的二组点都与他有边就为3 ,其他为inf。当然是错的,因为距离S为3 的点还必须确定前一个点是距离为2 的点,并且有可能出现距离为4 ,5,。。。。等等。所以GG

就比如这个样例:

1
5 6
1 3
1 4
1 5
2 4
2 5
3 5
1

当然做法就是两个set  维护,然后bfs就可以。每个点只可能出队列入队一次。

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N =200005;
const int inf =0x3f3f3f3f;

int n,m,S;
vector< int >ve[N];
set<int >se1;
set<int >se2;
int Ans[N];
set<int >::iterator it;

void init()
{
    memset(Ans,inf ,sizeof(Ans));
    for(int i=0;i<=n;i++) ve[i].clear();
    se1.clear(); se2.clear();
}

void bfs()
{
    queue< int >q;
    q.push(S);
    int u,v;
    Ans[S]=0;
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=0;i<ve[u].size();i++){
            v=ve[u][i];
            if(!se1.count(v)) continue;
            se2.insert(v);
            se1.erase(v);
        }
        for( it=se1.begin();it!=se1.end();it++)
        {
            v=*it;
            if(Ans[v]>Ans[u]+1) Ans[v]=Ans[u]+1;
            q.push(v);
        }
        swap(se1,se2);
        se2.clear();
    }

    int cnt=0;
    for(int i=1;i<=n;i++){
        if(i==S) continue;
        if(Ans[i]==inf) printf("-1");
        else printf("%d",Ans[i]);
        ++cnt;
        if(cnt==n-1) printf("\n");
        else printf(" ");
    }

}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        int u,v;
        init();
        for(int i=1;i<=m;i++){
            scanf("%d %d",&u,&v);
            ve[u].push_back(v);
            ve[v].push_back(u);
        }
        scanf("%d",&S);
        for(int i=1;i<=n;i++){
            if(i==S) continue;
            se1.insert(i);
        }

        bfs();

    }
    return 0;
}


/*

1
5 6
1 3
1 4
1 5
2 4
2 5
3 5
1

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值