• 分道扬镳 /// 邻接表 DFS 剪枝 oj1332


    题目大意:

    编号为1…N 的N个城市之间以单向路连接,每一条道路有两个参数:路的长度和通过这条路需付的费用。

    Bob和Alice生活在城市1,但是当Bob发现了Alice玩扑克时欺骗他之后,他决定与她翻脸,离开城市1前往城市N。Bob想尽快到达城市N,但是他的钱不多。

    希望你帮助Bob找到一条从城市1到城市N的总费用不超过Bob的承受能力的最短路径。

    Input

    输入的第一行是3个整数 K, N, R ,其中:

        K:表示Bob能承受的最大费用,0 ≤ K ≤ 10000

        N:表示城市的总数,2 ≤ N ≤ 100

        R:表示道路的条数,1 ≤ R ≤ 10000

    接下来的R行,每行用S  D  L  T(以空格隔开)表示一条道路:

        S:表示道路的出发城市,1 ≤ S ≤ N

        D:表示道路的目标城市,1 ≤ D ≤ N

        L:表示道路的长度,1 ≤ L ≤ 100

        T:表示通过这条道路需付的费用,0 ≤ T ≤ 100

    Output

    为每个测试用例输出一行结果:总费用小于或等于最大费用K的最短路径的长度。如果这样的路径不存在,则仅仅输出 -1 。

    Sample Input

    5 6 7
    1 2 2 3
    2 4 3 3
    3 4 2 4
    1 3 4 1
    4 6 2 1
    3 5 2 0
    5 4 3 2

    Sample Output

    11

    Hint

    测试数据的图中可能有重边、有自环

     
    原本天真地以为邻接表+DFS+简单剪枝就能过 结果还是TLE
    之前看题解发现了一个 特殊的剪枝 用上就AC了
     
     minlen[node][fee]数组记录1~ node 点在 fee 花费时的最短距离
    假如搜索到 i 点而花费为 fe 时 le 超过了已记录到的 minlen[i][fe] 则可结束本次搜索
    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    using namespace std;
    
    int s[10005],d[10005],l[10005],t[10005],flag[105];
    int k,n,r,len,minlen[105][10005],first[105],nexti[10005];
    
    void DFS(int i,int le,int fe)
    {
        if(fe>k || le>minlen[i][fe] || le>len) return;
     /// 用minlen数组记下 i 点在 fe 花费时的最短距离,若超过则可停止继续搜索了
    
        if(i==n)
        {
            len=min(len,le);
            //printf("%d
    ",len);
            return ;
        }
        else
        {
            if(le<minlen[i][fe]) /// 若存在更短的距离 则更新minlen的值
                for(int j=fe;j<=k;j++) 
                    minlen[i][j]=le;
    
            int in=first[i];
            while(in!=-1)
            {
                if(!flag[d[in]])
                {
                    flag[d[in]]=1; /// 避免自环情况
                    DFS(d[in],le+l[in],fe+t[in]);
                    flag[d[in]]=0;
                }
                in=nexti[in];
            } /// 邻接表遍历
    
        }
    
    }
    int main()
    {
        while(~scanf("%d%d%d",&k,&n,&r))
        {
            memset(flag,0,sizeof(flag));
            for(int i=1;i<101;i++)
                for(int j=0;j<10001;j++)
                    minlen[i][j]=200000;
            memset(first,-1,sizeof(first));
    
            for(int i=1;i<=r;i++)
            {
                scanf("%d%d%d%d",&s[i],&d[i],&l[i],&t[i]);
                nexti[i]=first[s[i]];
                first[s[i]]=i;
            } /// 建邻接表 可避免重边引起的错误
    
            flag[1]=1; len=INF;
            DFS(1,0,0);
    
            if(len==INF) printf("-1
    ");
            else printf("%d
    ",len);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    MySQL 5.7笔记
    Golang学习笔记
    Ubuntu使用笔记
    Linux下安装nginx和php
    Eclipse远程调试Java程序
    CentOS下glibc更新
    Linux服务器运行环境搭建(三)——MySQL数据库安装
    Linux服务器运行环境搭建(二)——Redis数据库安装
    Linux下定时任务Crontab的使用
    Linux下nginx安装与配置
  • 原文地址:https://www.cnblogs.com/zquzjx/p/8605948.html
Copyright © 2020-2023  润新知