poj3635 Full Tank? 最短路+dp

思路:根据题意很容易想到动态规划方程,,状态dp[i][j]表示到达i时油量剩余j,但是复杂度太高。

从另一个角度想,由一个最优解产生另一个最优解,每次取最优解的节点进行扩展,类似dijkstra最短路。

具体处理如下:

每次取一个最优节点出队,则节点为队中到源点花费最小的,在该状态下,可以选择购买1单位的油,也可以走向其邻节点。为什么是购买1单位的油?假设此时队首油量为j,在该点最多可以购买capacity - j的油,每次增加1个单位,最多再有capacity - j个节点入队,而若每次取出节点时就枚举所有购买的可能性,会造成队列中大量重复节点,故每次只增加一单位。

代码如下:

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define N 1005
#define M 10005
#define C 105
#define INF 0x3f3f3f3f
#define min(a, b) (a) < (b) ? (a) : (b)
int cnt, p[N], head[N], dis[N][C];
bool ins[N][C];
struct Node{
	int u, fuel, cost;
	Node(int uu, int f, int c): u(uu), fuel(f), cost(c) {}
	friend bool operator< (const Node& n1, const Node& n2){
		return n1.cost > n2.cost;
	}
};
struct Edge{
	int to, next, d;
}e[M * 2];

void add(int from, int to, int d){
	++cnt;
	e[cnt].to = to, e[cnt].d = d, e[cnt].next = head[from], head[from] = cnt;
}

int dijkstra(int source, int dest, int capacity){
	memset(dis, INF, sizeof(dis));
	memset(ins, false, sizeof(ins));
	priority_queue<Node> pq;
	pq.push(Node(source, 0, 0));
	while(!pq.empty()){
		Node cur = pq.top();
		pq.pop();
		int u = cur.u, fuel = cur.fuel, cost = cur.cost;
		if(ins[u][fuel])
			continue;
		ins[u][fuel] = true;
		if(u == dest)
            return cost;
		if(fuel + 1 <= capacity && !ins[u][fuel + 1] && dis[u][fuel + 1] > cost + p[u]){
            pq.push(Node(u, fuel + 1, cost + p[u]));
            dis[u][fuel + 1] = cost + p[u];
		}
		for(int i = head[u]; i != 0; i = e[i].next){
			int to = e[i].to, d = e[i].d;
			if(fuel >= d && dis[to][fuel - d] > cost && !ins[to][fuel - d] && dis[to][fuel - d] > cost){
                pq.push(Node(to, fuel - d, cost));
                dis[to][fuel - d] = cost;
			}
		}
	}
	return -1;
}

int main(){
	int n, m;
	scanf("%d %d", &n, &m);
	for(int i = 0; i < n; ++i)
		scanf("%d", &p[i]);
	for(int i = 0; i < m; ++i){
		int from, to, d;
		scanf("%d %d %d", &from, &to, &d);
		add(from, to, d);
		add(to, from, d);
	}
	int q;
	scanf("%d", &q);
	for(int i = 0; i < q; ++i){
		int s, e, c;
		scanf("%d %d %d", &c, &s, &e);
		int res = dijkstra(s, e, c);
		if(res == -1)
			printf("impossible\n");
		else
			printf("%d\n", res);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值