Sparse Graph HDU - 5876

http://acm.hdu.edu.cn/showproblem.php?pid=5876

给一个无权无向图 求原点到其他点的最短路 建补图是不可能的 只能从原图入手

考虑将所有点划分为两个集合 一个是已经知道与原点最短距离的记为A 另一个未知记为B 扫一遍A中所有点 遍历他们的原图邻接边 对所有邻接点标记加一 然后看B中有哪些点和A中所有点都有原图边 这些点在当前是不可能被松弛的 B中剩下的点作为下一轮的A继续遍历 当前这一轮的A已经完成任务可以清空 因为能被他们松驰的点在当前这一轮都被拿到新A中 对新B中的点已经没有意义

具体实现用队列即可 一个点出入队列各一次 复杂度o(n+m)

#include <bits/stdc++.h>
using namespace std;
#define ll long long

struct node
{
    int v;
    int next;
};

queue <int> que1,que2,que3,que4;
node edge[40010];
int first[200010],dis[200010],book[200010],cnt[200010];
int n,m,num,s;

void addedge(int u,int v)
{
    edge[num].v=v;
    edge[num].next=first[u];
    first[u]=num++;
}

int main()
{
    int t,i,u,v,cur,sz;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(first,-1,sizeof(first));
        num=0;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        scanf("%d",&s);
        while(!que1.empty()) que1.pop();
        while(!que2.empty()) que2.pop();
        memset(dis,-1,sizeof(dis));
        memset(book,0,sizeof(book));
        memset(cnt,0,sizeof(cnt));
        que1.push(s);
        for(i=1;i<=n;i++) if(i!=s) que2.push(i);
        dis[s]=0;
        cur=1;
        while(!que1.empty()&&!que2.empty())
        {
            //printf("***%d***\n",cur);
            while(!que3.empty()) que3.pop();//yes
            while(!que4.empty()) que4.pop();//no yet
            sz=que1.size();
            while(!que1.empty())
            {
                u=que1.front();
                que1.pop();
                for(i=first[u];i!=-1;i=edge[i].next)
                {
                    v=edge[i].v;
                    if(book[v]!=cur) cnt[v]=1;
                    else cnt[v]++;
                    book[v]=cur;
                }
            }
            while(!que2.empty())
            {
                u=que2.front();
                que2.pop();
                if(book[u]!=cur||(book[u]==cur&&cnt[u]<sz))
                {
                    que3.push(u);
                    //printf("#3 %d\n",u);
                    dis[u]=cur;
                }
                else
                {
                    //printf("#4 %d\n",u);
                    que4.push(u);
                }
            }
            while(!que3.empty())
            {
                u=que3.front();
                que3.pop();
                que1.push(u);
            }
            while(!que4.empty())
            {
                u=que4.front();
                que4.pop();
                que2.push(u);
            }
            cur++;
        }
        cur=1;
        for(i=1;i<=n;i++)
        {
            if(i!=s)
            {
                printf("%d",dis[i]);
                if(cur<n-1) printf(" ");
                else printf("\n");
                cur++;
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值