Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible!
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Each line contains four space-separated entities, F1,
F2, L, and D that describe a road. F1 and F2 are numbers of
two farms connected by a road, L is its length, and D is a
character that is either 'N', 'E', 'S', or 'W' giving the
direction of the road from F1 to F2.
* Line 2+M: A single integer, K. 1 <= K <= 10,000
* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.
* Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6
13
3
36
Farms 2 and 6 are 20+3+13=36 apart.
USACO 2004 February
/*算法思想: 刚开始的时候没有一点思路,听了老师们的讲解之后理论上是懂了,但是实现起来却花了不少时间 做法是给每个点处记录两个值:一个是到达这个点的花费,一个是到达这个点还剩下的油量,在每个点有两个操作: 1、加一升油 2、开往下一个点 加油之后,这个状态要加入优先队列中,因为它可能会更新其他状态的最小代价,而开往下一个节点的状态也要加入优先队列中, 这样其实就是一个BFS了,我觉得更像是一个A*的BFS。这样一旦BFS到了目标节点就直接退出BFS过程。 直接退出的原因是因为这是一个按照代价排序的优先队列,当前出队的代价一定是队中所有节点代价最小的,那么,第一次BFS到 目标节点就得出了到达目标节点的最小代价。 设置了一个数组 dis[i][j] 表示到达节点 i 还剩下 j 升油, 再设置一个数组 vs[i][j] 表示到达节点 i 还剩下 j 升油这个状态是否访问过,这样就相当于是把每个节点拆成了 cap+1 个节点了。 */ /*code*/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define N 2000 #define INF 0x7fffffff using namespace std; struct data { int en,val,next; }edge[N*100]; struct node { int v,cap,cost; //节点的编号v,到达此节点还剩的油cap,到达此节点的花费cost bool operator < (const node &a) const //囧了,刚开始没有重载运算符,一直没过样例,改了之后总算1y了 { return a.cost<cost; } }; int dis[N][105],head[N],p[N]; int n,m,tot,cap; bool vs[N][105]; void add_edge(int st,int en,int val) //加边 { edge[tot].en=en; edge[tot].val=val; edge[tot].next=head[st]; head[st]=tot++; } int dijstra(int s,int t) //dijstra过程 { priority_queue<node>q; q.push({s,0,0}); while(!q.empty()) { node now=q.top(); q.pop(); if(now.v==t) return now.cost; vs[now.v][now.cap]=true; if(now.cap+1<=cap && !vs[now.v][now.cap+1] && dis[now.v][now.cap+1]>dis[now.v][now.cap]+p[now.v])//加一升油 { dis[now.v][now.cap+1]=dis[now.v][now.cap]+p[now.v]; q.push({now.v,now.cap+1,dis[now.v][now.cap+1]}); } for(int i=head[now.v];i!=-1;i=edge[i].next) //从当前状态出发,遍历能够遍历的点 { if(now.cap>=edge[i].val && !vs[edge[i].en][now.cap-edge[i].val] && dis[edge[i].en][now.cap-edge[i].val]>now.cost)//油足够时 { dis[edge[i].en][now.cap-edge[i].val]=now.cost; q.push({edge[i].en,now.cap-edge[i].val,now.cost}); } } } return -1; //找不到路径 } int main() { scanf("%d%d",&n,&m); tot=0; memset(head,-1,sizeof(head)); for(int i=0;i<n;i++) scanf("%d",&p[i]); int a,b,c; for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); add_edge(a,b,c); add_edge(b,a,c); } int q,s,t; scanf("%d",&q); while(q--) { scanf("%d%d%d",&cap,&s,&t); memset(vs,0,sizeof(vs)); for(int i=0;i<n;i++) for(int j=0;j<=cap;j++) dis[i][j]=INF; dis[s][0]=0; int ans=dijstra(s,t); if(ans!=-1) printf("%d\n",ans); else printf("impossible\n"); } return 0; }