码迷,mamicode.com
首页 > 编程语言 > 详细

POJ 1511 Invitation Cards 邻接表 spfa算法

时间:2015-08-10 16:14:11      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:图论

原题: http://poj.org/problem?id=1511

题目大意:
单向图,需要从点1到每个点去一次,去了马上回来,再去下一个点,求往返路径和。

如果只有100个点,跑一遍floyd就可以了,这里有10w个点,不行。
朴素的dijkstra是N^2的复杂度,这里要超时。
所以这里我们用spfa这种接近2N的算法。

由于二维数组空间不够,所以只能用vector或者邻接表,因为vector的适合经常修改,本身是链表结构,每次插入数据都会消耗时间来申请内存并和前面建立联系,虽然可以支持下标访问,但是效率肯定赶不上数组的下标访问,所以有时候用vector会超时,这里我们用邻接表来存。

由于我们要求原点到每个点的来回距离,求一遍spfa我们只能得到单向距离和,而返回的路怎么求呢?
先说我们再纸上画的情况,如下图例:
技术分享
我们以A为起点,跑一遍spfa能求出A到每个点的距离。
现在B到A的路只有一条,是B->C->D->A,如果我们把顺序反过来看,可以发现A->D->C->B是他的回路。如果我们把整个地图的箭头都反过来,再求一次spfa,那么就能得到最后的结果了。

参考代码如下:

#include"stdio.h"
#include"iostream"
#include"string.h"
#include"queue"
using namespace std;
typedef long long int lint;
const lint INF = 0x3F3F3F3F3F3F3F3F;
const int N= 1000005;

struct node
{
    int en;
    int len;
    int next;
};
int n,m;
bool vis[N];
lint dis[N];
int head1[N];
int head2[N];
node maze1[N];
node maze2[N];

void spfa1()
{
    memset(vis,false,sizeof(vis));
    for(int i=0; i<=n; i++)    dis[i]=INF;
    queue <int> q;
    dis[1]=0;
    vis[1]=true;
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=false;
        for(int i=head1[x];i!=-1;i=maze1[i].next)
        {
            int en=maze1[i].en;
            if(dis[en]>dis[x]+maze1[i].len)
            {
                dis[en]=dis[x]+maze1[i].len;
                if(vis[en]==false)
                {
                    vis[en]=true;
                    q.push(en);
                }
            }
        }
    }
}
void spfa2()
{
    memset(vis,false,sizeof(vis));
    for(int i=0; i<=n; i++)
        dis[i]=INF;
    queue <int> q;
    dis[1]=0;
    vis[1]=true;
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=false;
        for(int i=head2[x];i!=-1;i=maze2[i].next)
        {
            int en=maze2[i].en;
            if(dis[en]>dis[x]+maze2[i].len)
            {
                dis[en]=dis[x]+maze2[i].len;
                if(vis[en]==false)
                {
                    vis[en]=true;
                    q.push(en);
                }
            }
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        scanf("%d %d",&n,&m);
        for(int i=1; i<=m; i++)
        {
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            maze1[i].len=z;
            maze1[i].en=y;
            maze1[i].next=head1[x];
            head1[x]=i;

            maze2[i].len=z;
            maze2[i].en=x;
            maze2[i].next=head2[y];
            head2[y]=i;
        }
        lint ans=0;
        spfa1();
         for(int i=1; i<=n; i++)
        ans=ans+dis[i];
        spfa2();
            for(int i=1; i<=n; i++)
        ans=ans+dis[i];
        printf("%I64d\n",ans);
    }
    return 0;
}

下面是vector的写法,虽然对于本题的数据会超时,大家也可以参考一下:

#include"stdio.h"
#include"iostream"
#include"string.h"
#include"queue"
using namespace std;
typedef long long int lint;
const lint INF = 0x3F3F3F3F3F3F3F3F;
const int N= 1000005;

struct node
{
    int en;
    int len;
    int next;
};
int n,m;
bool vis[N];
lint dis[N];
int head1[N];
int head2[N];
node maze1[N];
node maze2[N];

void spfa1()
{
    memset(vis,false,sizeof(vis));
    for(int i=0; i<=n; i++)    dis[i]=INF;
    queue <int> q;
    dis[1]=0;
    vis[1]=true;
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=false;
        for(int i=head1[x];i!=-1;i=maze1[i].next)
        {
            int en=maze1[i].en;
            if(dis[en]>dis[x]+maze1[i].len)
            {
                dis[en]=dis[x]+maze1[i].len;
                if(vis[en]==false)
                {
                    vis[en]=true;
                    q.push(en);
                }
            }
        }
    }
}
void spfa2()
{
    memset(vis,false,sizeof(vis));
    for(int i=0; i<=n; i++)
        dis[i]=INF;
    queue <int> q;
    dis[1]=0;
    vis[1]=true;
    q.push(1);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=false;
        for(int i=head2[x];i!=-1;i=maze2[i].next)
        {
            int en=maze2[i].en;
            if(dis[en]>dis[x]+maze2[i].len)
            {
                dis[en]=dis[x]+maze2[i].len;
                if(vis[en]==false)
                {
                    vis[en]=true;
                    q.push(en);
                }
            }
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        scanf("%d %d",&n,&m);
        for(int i=1; i<=m; i++)
        {
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            maze1[i].len=z;
            maze1[i].en=y;
            maze1[i].next=head1[x];
            head1[x]=i;
            maze2[i].len=z;
            maze2[i].en=x;
            maze2[i].next=head2[y];
            head2[y]=i;
        }
        lint ans=0;
        spfa1();
         for(int i=1; i<=n; i++)
        ans=ans+dis[i];
        spfa2();
            for(int i=1; i<=n; i++)
        ans=ans+dis[i];
        printf("%I64d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ 1511 Invitation Cards 邻接表 spfa算法

标签:图论

原文地址:http://blog.csdn.net/qq_27508477/article/details/47399217

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!