六度空间(BFS及优化)

目录

1.错误的BFS

2.正确的BFS

3.层数记录优化


1.错误的BFS

题目不做描述了,听完陈姥姥讲完怎么记录层数后就直接开始码了,也正是这个记录层数直接废了我一个下午,下面附上我第一次写出来的BFS并最终通过了测试点。

# include <iostream>
# include<vector>
# include <queue>
# define MAX 1005
using namespace std;
vector<int> all[MAX];
bool f[MAX];
int n,m;
int main(){
    int i,j,a,b;
    cin>>n>>m;
    for(i=0;i<m;i++){
        cin>>a>>b;
        all[a].push_back(b);
        all[b].push_back(a);
    }

    for(i=1;i<=n;i++){
        queue<int> q;
        int cnt=0,last=i,level=0,tail=0;
        q.push(i);
        while(!q.empty()){
            int tmp=q.front();q.pop();
            if(!f[tmp]){
                f[tmp]=1;cnt++;
                if(level<6){
                    int pos=all[tmp].size();
                    for(j=0;j<pos;j++){
                        if(!f[all[tmp][j]]){
                            q.push(all[tmp][j]);
                            tail=all[tmp][j];
                        }
                    }
                    if(tmp==last){
                        level++;last=tail;
                    }
                }
            }
        }
        printf("%d: %.2lf%\n",i,cnt*1.0/n*100);
        for(j=0;j<MAX;j++)  f[j]=0;
    }

    return 0;
}

但是提交上去最后一个测试点一直是答案错误。搜的AC题解是在每次入队列前进行去重,注意到我这里没有进行标记,所以可能导致一个结点被多次入队,但是没有关系,我在出队列后进行了标记,按理来说应该没有问题。但是我忽略了一点:

如图,我们的入队顺序是从左到右,从上到下。用上面的代码7,8,9结点会被入队两次,在4结点连的7,8,9入队完了之后,结点9就会作为last。那么问题就来了, 在第一个9出队之后,就会错误地判断成第三层的last结点,但是实际上第三层还有5,6没有访问,就进行了下一层的循环。如果这种情况发生在第六层就会使最终结果小于实际值。

2.正确的BFS

在最终搞明白问题之后,我写出来正确的BFS。

for(i=1;i<=n;i++){
    queue<int> q;
    int cnt=0,last=i,level=0,tail=0;
    q.push(i);
    while(!q.empty()){
        int tmp=q.front();q.pop();
        f[tmp]=1;cnt++;
        if(level<6){
            int pos=all[tmp].size();
            for(j=0;j<pos;j++){
                if(!f[all[tmp][j]]){
                    f[all[tmp][j]]=1;
                    q.push(all[tmp][j]);
                    tail=all[tmp][j];
                }
            }
            if(tmp==last){
                level++;last=tail;
            }
        }
    }
}

3.层数记录优化

以下受这篇文章启发:深入剖析-06-图3 六度空间 (30 分)_xie_shu的博客-CSDN博客 

我上面说了第一个BFS的问题在于记录层数,那么回想陈姥姥给出的方法是怎样记录的,定义了三个变量,主要是level和last,在每次读到一个last之后就表示这一层已经遍历完了,然后level加1,并然last等于最后入队的结点。

那么我们可以用同样的方法,在每层结束之后向队列插入一个结束标识元素。该元素的值为非正数,其绝对值等于层数。

具体做法是在初始结点入队之后入队一个0,作为第0层的结束标识元素,然后读到了第0层的一个结点(第0层只有一个元素),然后将与其相连的结点入队,继续读取队列就发现了结束元素0,然后我们就向队列插入一个-1,如此循环,直到我们读到结束元素-6。

注意到,每一层有且只有一个结束元素,所以这种方法可以解决我的第一个BFS的问题。

以下附上代码:

for(i=1;i<=n;i++){
    queue<int> q;
    int cnt=0;
    q.push(i);q.push(0);
    while(!q.empty()){
        int tmp=q.front();q.pop();
        if(tmp==-6) break;
        if(tmp<1)   {q.push(tmp-1);continue;}
        if(!f[tmp]){
            f[tmp]=1;cnt++;
            int pos=all[tmp].size();
            for(j=0;j<pos;j++){
                if(!f[all[tmp][j]])
                    q.push(all[tmp][j]);
            }
        }
    }
    printf("%d: %.2lf%\n",i,cnt*1.0/n*100);
    for(j=0;j<MAX;j++)  f[j]=0;
}

当然,不管怎样将一个结点多次入队还是不划算的,还是要保证入队结点的唯一性。下面是最终代码:

for(i=1;i<=n;i++){
    queue<int> q;
    int cnt=0;
    q.push(i);q.push(0);
    while(!q.empty()){
        int tmp=q.front();q.pop();
        if(tmp==-6) break;
        if(tmp<1)   {q.push(tmp-1);continue;}
        f[tmp]=1;cnt++;
        int pos=all[tmp].size();
        for(j=0;j<pos;j++){
            if(!f[all[tmp][j]]){
                f[all[tmp][j]]=1;
                q.push(all[tmp][j]);
            }
        }
    }
    printf("%d: %.2lf%\n",i,cnt*1.0/n*100);
    for(j=0;j<MAX;j++)  f[j]=0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值