版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/GYH0730/article/details/82425836
题目链接:https://www.luogu.org/problemnew/show/P4009
【问题分析】
分层图最短路径问题。
【建模方法】
按照油箱中剩余油量建立K层图,汽车在地图上点i,剩余油量为l时,对应点为<i,l>。
1、如果油箱不满(l<K),点i为油库点,从<i,l>到<i.top>建立一条权值为A的有向边。
2、如果油箱不满(l<K),点i不为油库点,从<i,l>到<i.top>建立一条权值为A+C的有向边。
3、如果油箱不为空,i不为油库点,每层l从<i.l>到<j.l-1>建立一条权值为0的有向边,其中j为i的右边或下边相邻的一个顶点;从<i.l>到<j.l-1>建立一条权值为B的有向边,其中j为i的左边或上边相邻的一个顶点。
4、如果油箱不为空,i为油库点,从<i.K>到<j.K-1>建立一条权值为0的有向边,其中j为i的右边或下边相邻的一个顶点;从<i.K>到<j.K-1>建立一条权值为B的有向边,其中j为i的左边或上边相邻的一个顶点。
求从<(1,1),K>的单源最短路径,到达目标的最小费用就是Min{dist[<(N,N),k>] | 0 <= k <= K }
感觉第4条别管油箱空不空都需要建边,因为i为油库点已经加满油了
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4000005;
const int INF = 0x3f3f3f3f;
int n,k,a,b,c;
int is[105][105];
int to[4][2] = {1,0,0,1,-1,0,0,-1};
int tot,head[MAXN];
struct node
{
int to,next,w;
}edge[MAXN];
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void AddEdge(int u,int v,int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
struct HeapNode
{
int u,d;
HeapNode(){}
HeapNode(int _u,int _d)
{
u = _u;
d = _d;
}
bool operator < (const HeapNode& rhs) const
{
return d > rhs.d;
}
};
int dis[MAXN];
bool vis[MAXN];
void dijkstra(int s)
{
struct HeapNode t;
memset(dis,INF,sizeof(dis));
memset(vis,0,sizeof(vis));
priority_queue<HeapNode> pq;
pq.push(HeapNode(s,0));
dis[s] = 0;
while(!pq.empty()) {
t = pq.top();
pq.pop();
if(vis[t.u]) continue;
vis[t.u] = true;
int u = t.u;
for(int i = head[u]; i != -1; i = edge[i].next) {
int to = edge[i].to;
if(dis[to] > dis[u] + edge[i].w) {
dis[to] = dis[u] + edge[i].w;
pq.push(HeapNode(to,dis[to]));
}
}
}
}
int Point(int x,int y,int f)
{
return f * n * n + (x - 1) * n + y;
}
int main(void)
{
scanf("%d %d %d %d %d",&n,&k,&a,&b,&c);
init();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d",&is[i][j]);
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
for(int f = 0; f <= k; f++) {
int C = is[i][j] ? a : a + c;
if(f < k) AddEdge(Point(i,j,f),Point(i,j,k),C);
for(int q = 0; q < 4; q++) {
int tx = i + to[q][0];
int ty = j + to[q][1];
if(tx <= 0 || ty <= 0 || tx > n || ty > n) continue;
C = q < 2 ? 0 : b;
if(!is[i][j] && f > 0) AddEdge(Point(i,j,f),Point(tx,ty,f - 1),C);
else if(is[i][j]) AddEdge(Point(i,j,k),Point(tx,ty,k - 1),C);
}
}
}
}
dijkstra(Point(1,1,k));
int ans = 10000000;
for(int i = 0; i <= k; i++) {
ans = min(ans,dis[Point(n,n,i)]);
}
printf("%d\n",ans);
return 0;
}
直接BFS也能过,只在油量为空并且不能加油的情况下才建立加油厂
#include <bits/stdc++.h>
using namespace std;
int cost[105][105][15],mp[105][105],vis[105][105][15];
int to[8][2] = {{0,1},{1,0},{0,-1},{-1,0}};
int n,k,a,b,c;
struct node
{
int x,y;
int f,cost;
node(){}
node(int _x,int _y,int _cost,int _f)
{
x = _x;
y = _y;
cost = _cost;
f = _f;
}
bool operator <(const struct node& a) const
{
return cost > a.cost;
}
};
int ans;
void BFS()
{
struct node t;
cost[1][1][k] = 0;
priority_queue<node> pq;
pq.push(node(1,1,0,k));
while(!pq.empty()) {
t = pq.top();
pq.pop();
if(vis[t.x][t.y][t.f]) continue;
vis[t.x][t.y][t.f] = 1;
for(int i = 0; i < 4; i++) {
int tx = t.x + to[i][0];
int ty = t.y + to[i][1];
int tc,tf;
if(tx < 1 || ty < 1 || tx > n || ty > n) continue;
if(tx < t.x || ty < t.y) tc = t.cost + b;
else tc = t.cost;
if(tx == n && ty == n) {
ans = tc;
return;
}
tf = t.f - 1;
if(mp[tx][ty]) {
tf = k;
tc += a;
}
if(tf == 0) {
tf = k;
tc += (c + a);
}
pq.push(node(tx,ty,tc,tf));
}
}
}
int main(void)
{
scanf("%d %d %d %d %d",&n,&k,&a,&b,&c);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d",&mp[i][j]);
}
}
BFS();
printf("%d\n",ans);
return 0;
}