12
15
2015
0

【JSOI2015】地铁线路

首先,建图,所有地铁站点建n个点,然后每条线路的站点都建两个点,表示正向反向。

然后加边,易知边权有两个,一个是票价,一个是时间,我们用(票价,时间)来表示。每个站点下站,(0,0),上站(1,0),然后线路上相邻两点,(0,1)。第一问我们只要根据第一问做一次最短路即可,注意会卡spfa,需要用迪迦奥特曼(dijkstra)。第二问,我们根据第一问得到的dis,只需要保留dis[u]+cost[e]==dis[v]的边,易知新图是一张有向无环图,然后我们拓扑排序,根据第二个关键字求最长路即可。

他们都会stl,我只会手打堆。。。

代码:

 

#include<cstdio>
#include<string>
#include<map>
#include<algorithm>
#define INF 1000000000
using namespace std;
struct dui
{
    int x,id;
}d[10000010];
string str;
char s1[55],s2[55];
map<string,int> mp;
int n,s,x,cnt,m,edgenum,Edgenum,S,T,u,p1,p2;
int vet[10000010],next[10000010],head[5000010],tick[10000010],tim[10000010],Vet[10000010],Next[10000010],Head[5000010],Tim[10000010];
int q[5000010],dis[5000010],du[5000010],Min[5000010],flag[5000010];
void add(int u,int v,int w1,int w2)
{
    edgenum++;
    vet[edgenum]=v;
    next[edgenum]=head[u];
    head[u]=edgenum;
    tick[edgenum]=w1;
    tim[edgenum]=w2;
}
void Add(int u,int v,int w)
{
    Edgenum++;
    Vet[Edgenum]=v;
    Next[Edgenum]=Head[u];
    Head[u]=Edgenum;
    Tim[Edgenum]=w;
}
void shiftdown(int i,int n)
{
    while (i*2<=n)
    {
        int t=i*2;
        if (t+1<=n&&d[t+1].x<d[t].x) t++;
        if (d[i].x>d[t].x)
        {
            q[d[i].id]=t;
            q[d[t].id]=i;
            swap(d[i],d[t]);
            i=t;
        }else break;
    }
}
void shiftup(int i)
{
    while (i>1)
    {
        int t=i/2;
        if (d[i].x<d[t].x)
        {
            q[d[i].id]=t;
            q[d[t].id]=i;
            swap(d[i],d[t]);
            i=t;
        }else break;
    }
}
int main()
{
    scanf("%d%d",&s,&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%s",s1);
        str=s1;
        mp[str]=i;
    }
    cnt=n;
    for (int i=1;i<=s;i++)
    {
        scanf("%d",&x);
        for (int j=1;j<=x;j++)
        {
            scanf("%s",s1);
            str=s1;
            u=mp[str];
            add(cnt+j,u,0,0);
            add(u,cnt+j,1,0);
            add(cnt+j+x,u,0,0);
            add(u,cnt+j+x,1,0);
        }
        cnt+=2*x;
        for (int j=2;j<=x;j++) add(cnt-j-x+1,cnt-j-x+2,0,1);
        for (int j=1;j<x;j++) add(cnt-j+1,cnt-j,0,1);
    }
    scanf("%s%s",s1,s2);
    str=s1;S=mp[str];
    str=s2;T=mp[str];
    for (int i=1;i<=cnt;i++)
        Min[i]=INF;
    Min[S]=0;
    m=cnt;
    for (int i=1;i<=cnt;i++)
    {
        d[i].x=Min[i];
        d[i].id=i;
        q[i]=i;
        shiftup(i);
    }
    for (int i=1;i<=cnt;i++)
    {
        int u=d[1].id;
        flag[d[1].id]=1;
        q[d[m].id]=1;
        d[1]=d[m];
        m--;
        shiftdown(1,m);
        for (int e=head[u];e;e=next[e])
        {
            int v=vet[e];
            if (!flag[v])
            if (Min[u]+tick[e]<Min[v])
            {
                Min[v]=Min[u]+tick[e];
                d[q[v]].x=Min[v];
                shiftup(q[v]);
            }
        }
    }
    if (Min[T]>=INF) {printf("-1\n0\n");return 0;}
    printf("%d\n",Min[T]);
    for (int i=1;i<=cnt;i++)
    {
        for (int e=head[i];e;e=next[e])
        {
            int v=vet[e];
            if (Min[i]+tick[e]==Min[v]) {Add(i,v,tim[e]);du[v]++;}
        }
    }
    for (int i=1;i<=cnt;i++)
        dis[i]=-INF;
    for (int i=1;i<=cnt;i++)if (!du[i]) q[++p2]=i;
    while (p1<p2)
    {   
        p1++;
        u=q[p1];
        for (int e=Head[u];e;e=Next[e])
        {
            int v=Vet[e];
            du[v]--;
            if (du[v]==0) q[++p2]=v;
        }
    }
    dis[S]=0;
    for (int i=1;i<=cnt;i++)
    {
        int u=q[i];
        for (int e=Head[u];e;e=Next[e])
        {
            int v=Vet[e];
            dis[v]=max(dis[v],dis[u]+Tim[e]);
        }
    }
    printf("%d\n",dis[T]);
}
Category: 最短路 | Tags:

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com