pku3635有一定大小的油箱从S到T所需最少的money

本文介绍了一种解决特定场景下的最短路径问题的方法,即在一个包含多个节点和边的图中,考虑到每个节点有不同的加油成本,求解从起点到终点的最低成本路径。文章通过使用优先队列实现Dijkstra算法的变体来解决这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        题意:现有N个点(n<=1000),m条边(m<=10000),在每个点都可以加油,告诉你每个点加油的单价,现在有一些询问,每个询问有油箱大小,始点,终点。输出每个询问的最小费用,不可能输出impossible.

        注意:使用优先队列(排序也是一样,反正用到堆的)时,注意你比较的值插入队列后就不要改变,因为如果改变了,但它在队列中的位置仍不变,那么就会不对应,导致出错。

        分析:对于每个查询,有状态mo[i][j]在i城市还剩油j所用的最少的钱

#include<stdio.h>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

const int maxn=1100;
const int maxm=11000;
const int maxc=110;
const int maxint=0x3fffffff;
struct point
{
	int u,v,w,c;
}p0,p1;
vector<point> e[maxn];
int n,c,s,t,mo[maxn][maxc],a[maxn];
bool operator >(point a,point b)
{
	return a.w>b.w;//这里不能用mo[a.v][a.c]>mo[b.v][b.c],
}
priority_queue <point,vector<point>,greater<point> >p;

void S()
{
	int i,j,k;
	bool tag;
	while(!p.empty())
		p.pop();
	
	for(i=0;i<n;i++)
		for(j=0;j<=c;j++)
			mo[i][j]=maxint;

	mo[s][0]=0;
	p0.v=s;
	p0.c=0;
	p0.w=0;
	p.push(p0);
	tag=false;
	while(!p.empty())
	{
		p0=p.top();
		p.pop();
		if(p0.w!=mo[p0.v][p0.c])//费用不是最少时,说明前面已经有最少的往后更新了,所以没用了
			continue;
		j=p0.v;
		if(j==t)
		{
			tag=true;
			printf("%d\n",p0.w);
			break;
		}
		if(p0.c+1<=c&&mo[j][p0.c+1]>mo[j][p0.c]+a[j])
		{
			mo[j][p0.c+1]=mo[j][p0.c]+a[j];
			p1.v=j,p1.c=p0.c+1,p1.w=mo[j][p1.c];
			p.push(p1);
		}
		for(i=0;i<e[j].size();i++)
		{
			if(p0.c<e[j][i].w) continue;
			k=e[j][i].v;
			if(mo[k][p0.c-e[j][i].w]>mo[j][p0.c])
			{
				mo[k][p0.c-e[j][i].w]=mo[j][p0.c];
				p1.v=k,p1.c=p0.c-e[j][i].w;
				p1.w=mo[k][p1.c];
				p.push(p1);
			}
		}
	}
	if(!tag)
		printf("impossible\n");
}
int main()
{
	int m,q,i;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(i=0;i<n;i++)
		{
			e[i].clear();
			scanf("%d",&a[i]);
		}
		for(i=0;i<m;i++)
		{
			scanf("%d%d%d",&p0.u,&p0.v,&p0.w);
			e[p0.u].push_back(p0);
			swap(p0.u,p0.v);
			e[p0.u].push_back(p0);
		}
		scanf("%d",&q);
		while(q--)
		{
			scanf("%d%d%d",&c,&s,&t);
			S();
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值