最少汽油

题面:

有n个城市,编号0至n-1。每个城市都有且仅有一个加油站,每个加油站都能提供无限多的汽油,第i个加油站的油价是p[i]元每升。你汽车的油箱容量是tank升,一开始汽车油箱没有汽油,你要从0号城市出发,目标是到达1号城市。城市之间总共有m条双向道路,例如:u,v,w,表示城市u和城市v之间有一条双向道路,行使这条道路要消耗w升汽油。注意:你要保证汽车行使在道路过程中不能因为油箱的汽油不够而抛锚,那是不容许的,因为只有在城市才有加油站,在道路中途是没有加油站的。输出你能完成任务的最小费用,如果不可能完成任务,输出-1。

思路:

首先,最simple的做法是跑dp(忽略爆搜)。我们记f[i][j]为当前在i节点,然后目前有j升汽油时最小的费用。首先我们忽略空间复杂度(50 * 1000000 * 8字节显然过不了256M)。

我们考虑转移,我们用类似于最短路dijkstra的方法进行转移(就是把每个状态看作一个点),对于每个状态f[i][j],枚举下一个点v,以及到那里时的汽油k,通过f[i][j]转移到f[v][k].

具体转移如下(G[i][j]表示i,j之间的路程)

当p[i]<p[v]:

f[v][k]=min(f[i][j]+(k+G[i][v]-j)*p[i]); (k+G[i][v]<=tank)//也就是在当前节点买够再出发。
f[v][k]=min(f[i][j]+(tank-j)*p[i]+(G[i][v]+k-tank)*p[v]);(k+G[i][v]>tank)//因油箱容量不足,所以买满再出发,到目的地再买到k

当p[i]>=p[v]:

f[v][k]=min(f[i][j]+(G[i][v]-j)*p[i]+k*p[v]); (G[i][v]>j)//当前点油不够,当前点买够路上的油,到了再买。
f[v][k]=min(f[i][j]+(k+G[i][v]-j)*p[v]); (G[i][v]<=j)//当前点油足够,直接过去再买。

好,现在我们来算算时间复杂度。

枚举i,j,v,k,完了,O(50* 1000000 * 50 * 1000000),人生苦短。

优化:

我们考虑瓶颈在何处,瓶颈显然是油箱容量和边长度太大了,明显正解时间复杂度与此无关。

其实呢,我们发现我们记录的j很多状态是无用的,比如对于某个节点i,它到终点的距离是100,那么我们f[i][101]显然是没用的。

我们考虑哪些是有用的,易发现我们j只用记录O(n)个,分别是i到其它点的距离。(当然0和tank也要记录)

证明如下:

比如我们要求i到v要花费的最少钱,我们考虑中转点k

如果我们中转点不买油,显然我们i到v走最短路最优,然后要记录的容量正好是i到v的距离。

否则,如果要在k买油,那么k买油一定是比在i买油更优的,我们可以考虑先从i转移到k,再从k转移到v。

那么做法便显然了。

用f[i][j]记录当前再点i,有G[i][j]那么多的汽油的最小花费。

然后就同上面类似的转移就行了。

时间复杂度把两个1e6优化成了两个50,时间复杂度O(n^4)

可以通过本题。

代码:

#include<bits/stdc++.h>
#define int long long 

using namespace std;
int n,m,tank;
int p[55];
int G[55][55];
long long f[55][55];
vector<int> son[55];
bool pd[55][55];
struct data{
	int u;
	int now;
	bool operator < (data const &A) const
	{return (u<A.u);};
};
signed main(){
	scanf("%lld%lld%lld",&n,&m,&tank);
	for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			G[i][j]=1e9;
	for(int i=1;i<=n;i++)
		G[i][n+1]=tank;
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%lld%lld%lld",&u,&v,&w);
		u++,v++;
		G[u][v]=min(G[u][v],w);
		G[v][u]=min(G[v][u],w);
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
	if(G[1][2]==1e9){
		puts("-1");
		return 0;
	}
	for(int i=1;i<=n;i++){
		priority_queue<pair<int,int> >q;
		while(!q.empty())q.pop();
		for(int j=1;j<=n;j++)
			if(i!=j&&G[i][j]!=1e9&&G[i][j]<=tank)q.push(make_pair(-G[i][j],j));
		son[i].push_back(0);
		while(!q.empty()){
			son[i].push_back(q.top().second);
			q.pop();
		}
		son[i].push_back(n+1);
	}
	priority_queue<pair<long long,data> >q;
	while(!q.empty())q.pop();
	memset(f,127,sizeof(f));
	for(int i=0;i<son[1].size();i++)
		f[1][i]=G[1][son[1][i]]*p[1],q.push(make_pair(-f[1][i],(data){1,i}));
	while(!q.empty()){
		data U=q.top().second;
		q.pop();
		if(pd[U.u][U.now])continue;
		pd[U.u][U.now]=true;
		for(int i=1;i<=n;i++){
			if(G[U.u][i]>tank)continue;
			if(U.u==i){
				for(int j=U.now+1;j<son[U.u].size();j++){
					if(f[U.u][U.now]+(G[U.u][son[U.u][j]]-G[U.u][son[U.u][U.now]])*p[U.u]<f[U.u][j]){
						f[U.u][j]=f[U.u][U.now]+(G[U.u][son[U.u][j]]-G[U.u][son[U.u][U.now]])*p[U.u];
						q.push(make_pair(-f[U.u][j],(data){U.u,j}));
					}
				}
			}
			else{
				if(p[U.u]<p[i]){
					for(int j=0;j<son[i].size();j++){
						if(G[i][son[i][j]]+G[U.u][i]<G[U.u][son[U.u][U.now]])continue;
						if(G[i][son[i][j]]+G[U.u][i]>tank){
							int ned1=tank-G[U.u][son[U.u][U.now]];
							int ned2=G[i][son[i][j]]-(tank-G[U.u][i]);
							if(f[U.u][U.now]+ned1*p[U.u]+ned2*p[i]<f[i][j]){
								f[i][j]=f[U.u][U.now]+ned1*p[U.u]+ned2*p[i];
								q.push(make_pair(-f[i][j],(data){i,j}));
							}
						}else{
							int ned=G[U.u][i]+G[i][son[i][j]]-G[U.u][son[U.u][U.now]];
							if(f[U.u][U.now]+ned*p[U.u]<f[i][j]){
								f[i][j]=f[U.u][U.now]+ned*p[U.u];
								q.push(make_pair(-f[i][j],(data){i,j}) );
							}
						}
					}
				}
				else{
					for(int j=0;j<son[i].size();j++){
						if(G[i][son[i][j]]+G[U.u][i]<G[U.u][son[U.u][U.now]])continue;
					if(G[U.u][son[U.u][U.now]]<G[U.u][i]){
						int ned1=G[U.u][i]-G[U.u][son[U.u][U.now]];
						int ned2=G[i][son[i][j]];
						if(f[U.u][U.now]+ned1*p[U.u]+ned2*p[i]<f[i][j]){
							f[i][j]=f[U.u][U.now]+ned1*p[U.u]+ned2*p[i];
							q.push(make_pair(-f[i][j],(data){i,j}));
						}
					}else{
						int ned=G[i][son[i][j]]-G[U.u][son[U.u][U.now]]+G[U.u][i];
						if(f[U.u][U.now]+ned*p[i]<f[i][j]){
							f[i][j]=f[U.u][U.now]+ned*p[i];
							q.push(make_pair(-f[i][j],(data){i,j}));
						}
					}
				}
				}
			}
		}
	}
	long long ans=1e15;
	for(int i=0;i<son[2].size();i++){
		ans=min(ans,f[2][i]);
	}
	printf("%lld\n",ans);
	return 0;
}

上一篇:将exe和dll文件打包成单一的启动文件


下一篇:kafka auto.offset.reset参数解析