zoukankan      html  css  js  c++  java
  • 最少汽油

    题面:

    有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
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Mybatis入门
    java开发七大原则
    常用的一些实用类
    sql语句大全
    jsp中9个隐含对象
    解决POST和GET方式的中文乱码问题
    Servlet跳转页面的重定向和转发
    通用增删改查的方式
    IDEA 部署spring Cloud
    Oracle基础语法
  • 原文地址:https://www.cnblogs.com/Kiana-Kaslana/p/15541113.html
Copyright © 2011-2022 走看看