题意: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
*/