题解 SP50 【INCARDS - Invitation Cards】

· · 题解

题意简述:

求 1 号点到其他点的最短路和其他点到 1 号点的最短路。

思路:

第一眼想到 floyd 但是一看 1\le P,Q \le 1e6 直接暴毙。

再仔细观察题目,发现只需要求1到其他点的最短路其他点到1的最短路

你品,你细品。

举个栗子:样例第二组数据:

如果我们把这个图反过来建//add(y,x,z)

就成了这个模样:

我们惊奇的发现,倒过来建图之后,1 到其他点的最短路就是原来图的其他点到 1 的最短路!

Nice!让我们开始写代码。

代码

几点说明:

  1. 最短路为标准 Dijkstra ,spfa已死,Dijkstra当道!(其实这个题应该不卡 spfa )。
  2. 我采用链式前向星的方式建图,因为要建反图,前缀为 0 的是原图,为 1 的是反图。
#include<bits/stdc++.h>
#define F first
#define S second
using namespace std;
int n,m,nxt[2][1000006],cost[2][1000006],to[2][1000006],h[2][1000006],cnt1,cnt2;
void add(int x,int y,int z) {
    to[0][++cnt1]=y;
    to[1][++cnt2]=x;
    nxt[0][cnt1]=h[0][x];
    nxt[1][cnt2]=h[1][y];
    cost[0][cnt1]=z;
    cost[1][cnt2]=z;
    h[0][x]=cnt1;
    h[1][y]=cnt2;
}
priority_queue< pair<int,int> >q;
int dis[1000006];
bool vis[1000006];
int dijk(int opt) {
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    while(q.size()) q.pop();
    dis[1]=0;
    q.push(make_pair(0,1));
    while(q.size()) {
        int u=q.top().S;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=h[opt][u];i;i=nxt[opt][i]) {
            int v=to[opt][i];
            if(dis[v]>dis[u]+cost[opt][i]) {
                dis[v]=dis[u]+cost[opt][i];
                q.push(make_pair(-dis[v],v));
            }
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++)
        sum+=dis[i];
    return sum;
}
int main() {
    int t;
    cin>>t;
    while(t--) {
        memset(nxt,0,sizeof(nxt));
        memset(to,0,sizeof(to));
        memset(h,0,sizeof(h));
        memset(cost,0,sizeof(cost));
        cnt1=cnt2=0;
        cin>>n>>m;
        for(int i=1;i<=m;i++) {
            int x,y,z;
            cin>>x>>y>>z;
            add(x,y,z);
        }
        int ans1=dijk(0),ans2=dijk(1);
        cout<<ans1+ans2<<endl;
    }
    return 0;
}

其他

双倍经验放送:UVA721