【Nowcoder】2019牛客多校第四场 J free | 分层最短路、分层图模型

链接:https://ac.nowcoder.com/acm/contest/884/J
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Your are given an undirect connected graph.Every edge has a cost to pass.You should choose a path from S to T and you need to pay for all the edges in your path. However, you can choose at most k edges in the graph and change their costs to zero in the beginning. Please answer the minimal total cost you need to pay.

输入描述:

The first line contains five integers n,m,S,T,K.

For each of the following m lines, there are three integers a,b,l, meaning there is an edge that costs l between a and b.

n is the number of nodes and m is the number of edges.

输出描述:

An integer meaning the minimal total cost.

示例1

输入

复制

3 2 1 3 1
1 2 1
2 3 2

输出

复制

1

题目大意:给出点的个数n,边的个数m,起点s,终点t,然后你还可以使k条边的权值为0,问从s到e的最短路是多少。

题目思路:这个题题解的DP我没看懂就说一下用图论怎么做吧,我们可以分层建图,层与层之间 权值为0,表示用了一条边(单向边),层内保留原值建图。具体如下图所示:

【Nowcoder】2019牛客多校第四场 J free | 分层最短路、分层图模型_第1张图片

这样的话从第一层的起点1开始跑,跑到第二层的三需要1,第一层的3需要3,那么就表示使用一条边为0时,路程最短。具体这个题目就模拟一下建图过程就好了,然后用第一层的S作为起点,然后输出第k层E的最小值即可。这里注意分层建图之后,这就时最多 1000*1000个点,边数可能跟会到1e7所以head(链式前向星)数组还有边数组需要开到1e7否则会报错误,具体代码如下:

#include 
using namespace std;
typedef long long ll;
const ll INF=1e9+5;
const int maxn=1e7+8;
const double PI=acos(-1);
const ll mod=1e9+7;
ll n,m,s,ee,t;
int head[maxn];
bool vis[maxn];
ll dis[maxn];
struct node{
    ll e,next;
    ll w;
}edge[maxn];
ll cnt=0;
void addedge1(ll u,ll v,ll w)
{
    edge[cnt]=node{v,head[u],w};
    head[u]=cnt++;
    edge[cnt]=node{u,head[v],w};
    head[v]=cnt++;
}
void addedge(ll u,ll v,ll w)
{
    edge[cnt]=node{v,head[u],w};
    head[u]=cnt++;
}
void spfa(ll st)
{
    queueq;for(int i=1;i<=(t+1)*n;i++) vis[i]=false,dis[i]=INF;
    q.push(st);vis[st]=true;
    dis[st]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=false;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int e=edge[i].e;
            if(dis[e]>dis[u]+edge[i].w)
            {
                dis[e]=dis[u]+edge[i].w;
                if(!vis[e])
                {
                    vis[e]=true;
                    q.push(e);
                }
            }
        }
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&ee,&t);
    for(int i=1;i<=m;i++)
    {
        ll x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        addedge1(x,y,z);
        for(int k=1;k<=t;k++)//层内赋权值
            addedge1(k*n+x,k*n+y,z);
        ll tempx=x,tempy=y;
        for(int k=1;k<=t;k++)//层间负赋权值
        {
            addedge(tempx,k*n+y,0);
            addedge(tempy,k*n+x,0);
            tempx=k*n+x;
            tempy=k*n+y;
        }
    }
    spfa(s);
    ll minl=dis[ee];
    printf("%lld\n",dis[t*n+ee]);
    return 0;
}

总结:记住分层最短路!!!!

你可能感兴趣的:(最短路)