poj 1511 正反向建图

这个题目的意思是求从1到其他点的最短路径,然后求其他点到0的最短路径。刚开始想的时候觉得可不可以用Floyd做,然后看了一下点数范围到了1000000,太大了。然后这个题还是比较巧妙的,先求从1点开始的单源最短路径。然后用将边反着建一个图,然后再求一次从1点开始的单源最短路径。其实反着建图了,然后1到该点的最短路径就是该点到1的最短路径,其实反着建图了之后,其他点都变为了1,1变为了其他点,所以求其他点到1的距离就可以直接一个单源最短路径就可以求出来了。(不知道我讲清楚了了没有==)
代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define maxn 1000005
const int INF=0x3f3f3f3f;
struct Edge
{
    int to,next;
    long long w;
};
struct dl
{
    int to;
    long long w;
     bool operator < (const dl &t)const{
           return w>t.w;
     }
};
Edge e1[maxn];
Edge e2[maxn];
int head1[maxn];
int head2[maxn];
int vis[maxn];
double  dis[maxn];
priority_queue <dl> Q;
int main()
{
    int N;
    scanf("%d",&N);
    while(N--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        memset(head1,-1,sizeof(head1));
        memset(head2,-1,sizeof(head2));
        memset(e2,0,sizeof(e2));
        memset(e1,0,sizeof(e1));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<m;i++)
        {
            int from,to;
            double w;
            scanf("%d %d %lf",&from,&to,&w);
            e1[i].to=to;
            e1[i].w=w;
            e1[i].next=head1[from];
            head1[from]=i;
            e2[i].to=from;
            e2[i].w=w;
            e2[i].next=head2[to];
            head2[to]=i;
        }
        while(!Q.empty())
            Q.pop();
        for(int i=0;i<=n+2;i++)//因为这里dis是double型,然后用memset的话,不会被初始化为INF,会被初始化为一个小数。。
            dis[i]=0x3f3f3f3f;
        dis[1]=0;
        dl k;
        k.to=1;
        k.w=0;
        Q.push(k);
        while(!Q.empty())
        {
            dl t=Q.top();
            Q.pop();
            if(t.w!=dis[t.to]||vis[t.to])
                continue;
            vis[t.to]=1;
            for(int i=head1[t.to];i>-1;i=e1[i].next)
            {
                Edge c=e1[i];
                if(!vis[c.to]&&dis[c.to]>c.w+t.w)
                {
                    dis[c.to]=c.w+t.w;
                    Q.push(dl{c.to,dis[c.to]});
                }
            }
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
            ans+=dis[i];
        while(!Q.empty())
            Q.pop();
       for(int i=0;i<=n+2;i++)
            dis[i]=0x3f3f3f3f;
        memset(vis,0,sizeof(vis));
        dis[1]=0;
        dl d;
        d.to=1;
        d.w=0;
        Q.push(d);
        while(!Q.empty())
        {
            dl t=Q.top();
            Q.pop();
            if(t.w!=dis[t.to]||vis[t.to])
                continue;
            vis[t.to]=1;
            for(int i=head2[t.to];i>-1;i=e2[i].next)
            {
                Edge c=e2[i];
                if(!vis[c.to]&&dis[c.to]>c.w+t.w)
                {
                    dis[c.to]=c.w+t.w;
                    Q.push(dl{c.to,dis[c.to]});
                }
            }
        }
         for(int i=1;i<=n;i++)
            ans+=dis[i];
        cout<<ans<<endl;
    }
    return 0;
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值