UESTC Training for Graph Theory——E、Distance Queries

Distance Queries

Time Limit: 2000 ms Memory Limit: 65536 kB Solved: 65 Tried: 321

Description

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!

Input

* 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. 

Output

* Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.

Sample Input

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

Sample Output

13
3
36

Hint

Farms 2 and 6 are 20+3+13=36 apart.

Source

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;
}


 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值