「JOI 2018 Final」月票购买

JOI 所住的城市有 N 个车站,分别编号为 1::N。有 M条铁路,编号为 1..M。第I 条铁路双向连接车站 A 与车站 B,乘车费用为 C。

JOI 住在车站 S 附近,而 JOI 所在的 IOI 高中在车站 T 附近。他打算买一张月票往返这两个车站。当他买这张月票时,他需要选择一条在车站 S 与车站 T之间的乘车费用最小的路径。有了这张月票,JOI 可以无需额外费用,双向通过任意所选路径包含的铁路。

JOI 经常去在车站 U 与车站 V 附近的书店,因此他希望能买一张月票使得从车站 U 到车站 V 的花费最小。

当他要从车站 U 去往车站 V 时,他会选择一条从车站 U 到车站 V 的路径。对于路径上的每段铁路,如果这段铁路在月票指定的路径范围内,则费用为 0 ,否则费用为C 。每段铁路的费用和为 JOI 从车站 U 到车站 V 的总费用。

他想要知道,如果他买月票时选择了一条合适的路线,从车站 U到车站 V 的最小费用是多少。

你需要编写一个程序计算最小费用。

解:
真是一道好题目啊
首先我们有一个贪心策略 首先将所有最短路上的边设置为有向边 然后再跑最短路 但是这样做有问题 因为两条路可能在两条最短路上 这就很难受了
但是!!! 注意到 这是一条连续的路径 最短路的边一定是DAG DAG上搞事情 DP啊 最短路的题目 不是建立图就是考DP 想DP 而且是一个在最短路上搞的DP 注意到 题目的条件是在一条最短路上 而一条最短路的条件为 \(dis[u]==dis[v]+le[i]\)然后我们就可以DP了 在图上的DP一定是在一个top序列上DP 于是我们就想到了 将最短路作为top序列进行DP 具体实现可以利用\(dij\)来做

topp序列DAG DP

queue<int> q;
void DP() {
    for (int i = 1; i <= n; fu[i] = vu[i], fv[i] = vv[i], i++)
        if (!deg[i])
            q.push(i);
    while (q.size()) {
        int x = q.front();
        q.pop();
        ans = min(ans, min(fv[x] + vu[x], fu[x] + vv[x]));
        for (int i = las[x]; i; i = pre[i]) {
            int y = to[i];
            fu[y] = min(fu[y], fu[x]), fv[y] = min(fv[y], fv[x]);
            if (--deg[y] == 0)
                q.push(y);
        }
    }
}

code:

//
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define inf (ll)(1e17)
#define maxnn 2010000
ll las[maxnn],nex[maxnn],le[maxnn],tot,en[maxnn];

ll zlas[maxnn],znex[maxnn],zle[maxnn],ztot,zen[maxnn];
ll flas[maxnn],fnex[maxnn],fle[maxnn],ftot;
ll dis1[maxnn],dis2[maxnn],dis3[maxnn],dis4[maxnn];
ll n,m,s,t,u,v;
struct node
{
    int st,en;
    ll l;
    ll d;
}ed[maxnn];
int cnt;

void add(int a,int b,ll c)
{
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
    le[tot]=c;
}

void zadd(int a,int b,ll c)
{
    zen[++ztot]=b;
    znex[ztot]=zlas[a];
    zlas[a]=ztot;
    zle[ztot]=c;
}
typedef pair<ll ,int > P;
priority_queue<P ,vector<P>,greater<P> > Q;
void dij(ll *dis,int v)
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
    }
    dis[v]=0;
    Q.push(make_pair(dis[v],v));
    while(Q.size())
    {
        P s=Q.top();
        Q.pop();
        if(s.first!=dis[s.second]) continue;
        for(int i=las[s.second];i;i=nex[i])
        {
            int u=en[i];
            if(dis[u]>dis[s.second]+le[i])
            {
                dis[u]=dis[s.second]+le[i];
                Q.push(make_pair(dis[u],u));
            }
        }
    }
}
ll dis[maxnn];
ll f[maxnn][3];
ll ans=111111111000000;
void ddij(int v)
{
    for(int i=1;i<=n;i++)
    {
        f[i][0]=f[i][1]=inf;
    }
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
    }
    dis[v]=0;
    f[v][0]=dis3[v];
    f[v][1]=dis4[v];
    Q.push(make_pair(dis[v],v));
    while(Q.size())
    {
        P s=Q.top();
        Q.pop();
        if(s.first!=dis[s.second]) continue;
        for(int i=zlas[s.second];i;i=znex[i])
        {
            int u=zen[i];
            if(dis[u]==dis[s.second]+zle[i])
            {
                dis[u]=dis[s.second]+zle[i];
                f[u][0]=min(f[u][0],min(f[s.second][0],dis3[u]));
                f[u][1]=min(f[u][1],min(f[s.second][1],dis4[u]));
            }
            if(dis[u]>dis[s.second]+zle[i])
            {
                dis[u]=dis[s.second]+zle[i];
                f[u][0]=min(f[s.second][0],dis3[u]);
                f[u][1]=min(f[s.second][1],dis4[u]);
                Q.push(make_pair(dis[u],u));
            }
        }
    }
}
int main()
{
    ll x,y,z;
    scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&s,&t,&u,&v);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld%lld",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
        ed[++cnt].st=x;
        ed[cnt].en=y;
        ed[cnt].l=z;
    }
    dij(dis1,s);
    dij(dis2,t);
    dij(dis3,u);
    dij(dis4,v);
    for(int i=1;i<=cnt;i++)
    {
        if(dis1[ed[i].st]+dis2[ed[i].en]+ed[i].l==dis1[t])
        {
            zadd(ed[i].st,ed[i].en,ed[i].l);
        }
        if(dis1[ed[i].en]+dis2[ed[i].st]+ed[i].l==dis1[t])
        {
            zadd(ed[i].en,ed[i].st,ed[i].l);
        }
    }
    ddij(s);
    for(int i=1;i<=n;i++)
    {
        ans=min(ans,f[i][1]+dis3[i]);
        ans=min(ans,f[i][0]+dis4[i]);
    }
    ans=min(ans,dis3[v]);
    cout<<ans;
    
}

猜你喜欢

转载自www.cnblogs.com/OIEREDSION/p/11810672.html