zoukankan      html  css  js  c++  java
  • ACM-ICPC 2018 南京赛区网络预赛 L题(分层最短路)

    题目链接https://nanti.jisuanke.com/t/31001

    题目大意:给出一个含有n个点m条边的带权有向图,求1号顶点到n号顶点的最短路,可以使<=k条任意边的权值变为0。

    样例输入

    1
    5 6 1
    1 2 2
    1 3 4
    2 4 3
    3 4 1
    3 5 6
    4 5 2

    样例输出

    3


    解题思路:可以用两种做法,不过都差不多,应该算是同一种思路的不同写法。
    第一种是在建图时,将一个点拆成k个层次的点,应该总共有k+1层,每个相同层次的点按输入的边权连接,每个点可以向它能连接到的点的下一个层次连接一条边权为0的边,这样你每使一条边权值变为0,即相当于走到了下一层图,永远不能走回,当走到第k+1层图时即不能使用了,在这个含有k+1层图的大图里跑下最短路就可以得出答案了
    附上代码:
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll maxn=2200007;
    const ll inf=0x3f3f3f3f;
    struct qnode{
        int u;
        ll dis;
        bool operator<(const qnode &a)const{
            return dis>a.dis;
        }
        qnode(int a,ll b)
        {
            u=a;
            dis=b;
        }
    };
    struct node{
        int v,w,next;
    }edge[2*maxn];
    int n,m,k,tot=0,head[maxn];
    ll dis[maxn];
    void add(int u,int v,int w)
    {
        edge[tot].v=v;
        edge[tot].w=w;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
    }
    void dij()
    {
        priority_queue<qnode> que;
        memset(dis,inf,sizeof(dis));
        dis[1]=0;
        que.push(qnode(1,0));
        while(!que.empty())
        {
            int u=que.top().u;
            que.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v,w=edge[i].w;
                if(dis[v]>dis[u]+w)
                {
                    dis[v]=dis[u]+w;
                    que.push(qnode(v,dis[v]));
                }
            }
        }
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            scanf("%d%d%d",&n,&m,&k);
            for(int i=0;i<m;i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                for(int j=0;j<=k;j++)
                {
                    add(u+j*n,v+j*n,w); //同一层次的点用输入边权相连
                    if(j!=k)
                        add(u+j*n,v+(j+1)*n,0); //不同层次的点用0权值相连
                }
            }
            if(k>=m)
            {
                printf("0
    ");
                continue;
            }
            ll ans=inf;
            dij();
            for(int i=0;i<=k;i++)
                ans=min(ans,dis[n+i*n]);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    第二种是用最短路+dp思想,再开一维数组记录已经使用了几次使边的权值为0,也是跑下最短路就可以了。

    附上代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+7;
    const long long inf=0x3f3f3f3f;
    struct node{
        int v,w,next;
    }edge[2*maxn];
    struct qnode{
        int u,k;
        long long dis;
        bool operator<(const qnode &a)const{
            return dis>a.dis;
        }
        qnode(int a,int b,long long c)
        {
            u=a;
            k=b;
            dis=c;
        }
    };
    int n,m,k,tot=0,head[maxn];
    long long dis[maxn][15];
    void add(int u,int v,int w)
    {
        edge[tot].v=v;
        edge[tot].w=w;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
    }
    long long dijkstra()
    {
        priority_queue<qnode> que;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=k;j++)
            {
                dis[i][j]=inf;
            }
        }
        que.push(qnode(1,0,0));
        dis[1][0]=0;
        while(!que.empty())
        {
            int u=que.top().u,tempk=que.top().k;
            if(u==n)
                return dis[u][tempk];
            que.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v,w=edge[i].w;
                if(dis[u][tempk]+w<dis[v][tempk])  //同一层的最短路
                {
                    dis[v][tempk]=dis[u][tempk]+w;
                    que.push(qnode(v,tempk,dis[v][tempk]));
                }
                if(tempk<k)
                {
                    if(dis[u][tempk]<dis[v][tempk+1])  //如果将这条边权值变为0,就会进入tempk+1层
                    {
                        dis[v][tempk+1]=dis[u][tempk];
                        que.push(qnode(v,tempk+1,dis[v][tempk+1]));
                    }
                }
            }
        }
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&n,&m,&k);
            init();
            for(int i=0;i<m;i++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
            }
            printf("%lld
    ",dijkstra());
        }
        return 0;
    }
    View Code
  • 相关阅读:
    2018-2019-1 20165307 20165327 20165332 实验一 开发环境的熟悉
    2018-2019-1 20165332 《信息安全系统设计基础》第4周学习总结
    2018-2019-2 20165329 《网络对抗技术》Exp0 Kali安装 Week1
    20165311 20165329 20165334 实验五 通讯协议设计-1
    2018-2019-1 20165329 《信息安全系统设计基础》第九周学习总结
    20165329 20165311 20165334 实验四外设驱动程序设计
    20165329 mybash的实现
    20165329 实现mypwd
    2018-2019-1 20165329 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165329 《信息安全系统设计基础》第6周学习总结
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/9744404.html
Copyright © 2011-2022 走看看