POJ 1724 ROADS [dijkstra+heap]

题意:Bob现在有的钱数为M,他想从城市1到城市n,给出m条连接两个城市的有向边,并且给出路的长度w,和经过这条路要交的钱数c。问Bob能到达城市n的最短路径为多长。(总共扣的钱数必须不大于M)

思路:dijkstra+heap的应用,加上A*的约束条件。需要对dijkstra有很好的理解,蛮像dfs的。改普通的dij为:只要一边起点的当前花费钱数 + 这条边的花费钱数 <= coin,就让这边终点的信息加入heap.(普通的dij是终边的距离有变小才让其加入heap)。这样的话,就可能有很多的同一个城市的不同点(距离,花费不同)出现在heap中,这时,根据heap的性质,首先出列的必然是dis最小的点,这就保证了首先得到的必是满足c <= coin的到这城市的最短路径。

#include <iostream>
#include <queue>
using namespace std;
const int MAX=10050;
int T,N,M,k;  //  边数  点数
int edgeHead[MAX];
const int INF=100000000;//距离无穷大
struct{
    int v, w, m, next;
}edge[8*MAX];
struct node{
    int u;
    int dis;
    int m;
    bool operator < (const node &a) const{//  heap的重载 < 号的形式。
        return dis > a.dis;
    }
};
void add_edge(int v, int u, int w, int m){//  为dijkstra构造邻接表。
    edge[k].v = v;
    edge[k].w = w;
    edge[k].m = m;
    edge[k].next = edgeHead[u];
    edgeHead[u] = k ++;
}
int dijkstra(int s,int t){
    //bool vis[MAX];不设置访问的记录,因为是以花费为入队条件,每一个点的dis不一定最小
    //memset(vis,0,sizeof(vis));
    //vis[s] = 1;//不可加
    priority_queue<node> que;//  运用STL的优先队列。
    node a;
    a.u = s;
    a.dis = 0;
    a.m=0;
    que.push(a);//  加入第一个节点,即为起点。
    while(!que.empty()){ //  优化的话可以多加一个 (&& count < n) 的判断。
        node now = que.top();
        int u=now.u;
        que.pop();
        //vis[u] = true;
        if(u == t) return now.dis;
        for(int i = edgeHead[u]; i != 0; i = edge[i].next){
            int v = edge[i].v;
            //if(!vis[v] && now.m+edge[i].m<=M){
            if(now.m+edge[i].m<=M){
                a.u = v;
                a.dis = now.dis + edge[i].w;
                a.m=now.m+edge[i].m;
                que.push(a);
            }
        }
    }
    return -1;
}
int main(){
    int x,y,w,m;
    scanf("%d%d%d",&M,&N,&T);
    k=1;
    while(T--){
        scanf("%d%d%d%d",&x,&y,&w,&m);
        add_edge(y-1,x-1,w,m);
    }
    printf("%d\n",dijkstra(0,N-1));
    return 0;
}
/*测试:
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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值