POJ - 1724:ROADS

N cities named with numbers 1 ... N are connected with one-way roads. Each road has two parameters associated with it : the road length and the toll that needs to be paid for the road (expressed in the number of coins). 
Bob and Alice used to live in the city 1. After noticing that Alice was cheating in the card game they liked to play, Bob broke up with her and decided to move away - to the city N. He wants to get there as quickly as possible, but he is short on cash. 

We want to help Bob to find the shortest path from the city 1 to the city N that he can afford with the amount of money he has. 

Input

The first line of the input contains the integer K, 0 <= K <= 10000, maximum number of coins that Bob can spend on his way. 
The second line contains the integer N, 2 <= N <= 100, the total number of cities. 

The third line contains the integer R, 1 <= R <= 10000, the total number of roads. 

Each of the following R lines describes one road by specifying integers S, D, L and T separated by single blank characters : 

  • S is the source city, 1 <= S <= N 
  • D is the destination city, 1 <= D <= N 
  • L is the road length, 1 <= L <= 100 
  • T is the toll (expressed in the number of coins), 0 <= T <=100


Notice that different roads may have the same source and destination cities.

Output

The first and the only line of the output should contain the total length of the shortest path from the city 1 to the city N whose total toll is less than or equal K coins. 
If such path does not exist, only number -1 should be written to the output. 

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

题意:

N个城市,编号1到N。城市间有R条单向道路。 每条道路连接两个城市,有长度和过路费两个属性。 Bob只有K块钱,他想从城市1走到城市N。问最短共需要走多长的路。如果到不了N ,输出-1
2<=N<=100

0<=K<=10000

1<=R<=10000                                                       

每条路的长度 L, 1 <= L <= 100

每条路的过路费T , 0 <= T <= 100

先说一下时间超限的做法 !!!!!!

// -----------------  该种解法时间超限  ------------------
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
int K,N,R;//钱,城市,道路
struct Road {//城市
    int d,L,t;//终点、长度、过路费
};
vector< vector<Road> > G(110);//创建城市集:注意这里只能用括号而不能用中括号
int minLen;
int totalLen;//距离
int totalCost;//花费
int visited[110];//记忆数组

void dfs(int s)
{
    if(s==N){ // 出口:已到城市N
        minLen = min(minLen,totalLen);//更新最小距离
        return;//返回函数
    }
    for(int i = 0;i<G[s].size();++i){ //遍历所有城市所有出去的路
        Road r = G[s][i];//取出当前道路
        if(totalCost + r.t > K)//花费超限
            continue;//此路不行,换下条路
        if(!visited[r.d]){//该路的终点没有到达过
            totalLen += r.L;//更新距离
            totalCost += r.t;//更新花费
            visited[r.d] = 1;//将终点设为已访问过
            dfs(r.d);//在终点的基础上进行深搜
            visited[r.d] = 0;//回溯
            totalLen -= r.L;
            totalCost -= r.t;
        }
    }
}

int main()
{
    scanf("%d%d%d",&K,&N,&R);
    for(int i = 0;i<R;++i)
    {
        int s;//充当起点
        Road r;//创建节点
        scanf("%d%d%d%d",&s,&r.d,&r.L,&r.t);
        if(s != r.d){//起点和终点不重复
            G[s].push_back(r);//相当于使用邻接表来存储图
        }
    }
    memset(visited,0,sizeof(visited));//初始化
    totalLen = 0;//每次情况的总长度
    minLen = 1 << 30;//最短距离
    totalCost = 0;//花费
    visited[1] = 1;//将第一座城市设为已访问
    dfs(1);//从第一座城市来对图进行深搜
    if(minLen < (1<<30)) //可以到达
        printf("%d\n",minLen);
    else //无法到达
        printf("-1");
    return 0;
}

 结果       

 解题思路:

从城市 1开始深度优先遍历整个图,找到所有能到达 N 的走法, 选一个最优的。

最优性剪枝:

1) 如果当前已经找到的最优路径长度为L ,那么在继续搜索的过程中,总长度已经大 于等于L的走法,就可以直接放弃,不用走到底了

另一种通用的最优性剪枝思想 ---保存中间计算结果用于最优性剪枝:

2) 如果到达某个状态A时,发现前面曾经也到达过A,且前面那次到达A所花代价更 少,则剪枝。这要求保存到达状态A的到目前为止的最少代价。

用midL[k][m] 表示:走到城市k时总过路费为m的条件下,最优路径的长度。若在后 续的搜索中,再次走到k时,如果总路费恰好为m,且此时的路径长度已经超过 midL[k][m],则不必再走下去了。
 

// -----------------  进行了剪枝解决了时间超限问题  ------------------
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
int K,N,R;//钱,城市,道路
struct Road {//城市
    int d,L,t;//终点、长度、过路费
};
vector< vector<Road> > G(110);//创建城市集:注意这里只能用括号而不能用中括号
int minL[110][10010];//minL[i][j]表示从1到i点的,花销为j的最短路的长度
int minLen;
int totalLen;//距离
int totalCost;//花费
int visited[110];//记忆数组

void dfs(int s)
{
    if(s==N){ // 出口:已到城市N
        minLen = min(minLen,totalLen);//更新最小距离
        return;//返回函数
    }
    for(int i = 0;i<G[s].size();++i){ //遍历所有城市所有出去的路
        Road r = G[s][i];//取出当前道路
        if(totalCost + r.t > K)//花费超限:可行性剪枝
            continue;//此路不行,换下条路
        if(!visited[r.d]){//该路的终点没有到达过
            if (totalLen + r.L >= minLen) //最优性剪枝
                continue;
            if(totalLen + r.L >= minL[r.d][totalCost + r.t])//可行性剪枝
                continue;
            minL[r.d][totalCost+r.t] = totalLen + r.L;
            totalLen += r.L;//更新距离
            totalCost += r.t;//更新花费
            visited[r.d] = 1;//将终点设为已访问过
            dfs(r.d);//在终点的基础上进行深搜
            visited[r.d] = 0;//回溯
            totalLen -= r.L;
            totalCost -= r.t;
        }
    }
}

int main()
{
    scanf("%d%d%d",&K,&N,&R);
    for(int i = 0;i<R;++i)
    {
        int s;//充当起点
        Road r;//创建节点
        scanf("%d%d%d%d",&s,&r.d,&r.L,&r.t);
        if(s != r.d){//起点和终点不重复
            G[s].push_back(r);//相当于使用邻接表来存储图
        }
    }
    memset(visited,0,sizeof(visited));//初始化为0
    memset(minL,0x3f,sizeof(minL));//初始化为无穷大
    totalLen = 0;//每次情况的总长度
    minLen = 1 << 30;//最短距离
    totalCost = 0;//花费
    visited[1] = 1;//将第一座城市设为已访问
    dfs(1);//从第一座城市来对图进行深搜
    if(minLen < (1<<30)) //可以到达
        printf("%d\n",minLen);
    else //无法到达
        printf("-1");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱事顺利、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值