汽车加油行驶问题
Time Limit: 1 Sec Memory Limit: 128 MBDescription
给定一个 N*N的方形网格,设其左上角为起点◎,坐标为( 1,1),X轴向右为正, Y轴向下为正,每个方格边长为 1,如图所示。一辆汽车从起点◎出发驶向右下角终点▲,其坐标为( N,N)。在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:
(1)汽车只能沿网格边行驶,装满油后能行驶 K条网格边。出发时汽车已装满油,在起点与终点处不设油库。
(2)汽车经过一条网格边时,若其 X坐标或 Y坐标减小,则应付费用 B,否则免付费用。
(3)汽车在行驶过程中遇油库则应加满油并付加油费用 A。
(4)在需要时可在网格点处增设油库,并付增设油库费用 C(不含加油费用 A)。
(5)(1)~(4)中的各数 N、K、A、B、C均为正整数,且满足约束:2 ≤ N ≤ 100,2 ≤ K ≤ 10。设计一个算法,求出汽车从起点出发到达终点的一条所付费用最少的行驶路线。
对于给定的交通网格,计算汽车从起点出发到达终点的一条所付费用最少的行驶路线。
Input
文件的第一行是 N,K,A,B,C的值。第二行起是一个 N*N的 0-1方阵,每行 N个值,至 N+1行结束。方阵的第 i行第 j列处的值为 1表示在网格交叉点( i,j)处设置了一个油库,为 0时表示未设油库。各行相邻两个数以空格分隔。
Output
输出最小费用
Sample Input
Sample Output
Source
题意依然不加赘述,题解也不难说,就是比裸最短路多几种转移方式,我不说转移方程了,代码写得很漂亮。
1 . 根据方向的不同要有一个费用B。
2 . 加油站问题,即可以把油量转移成满,注意用不用建即可。
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 105
#define K 15
#define inf 0x3f3f3f3f
using namespace std;
const int dx[4]={1,0,-1,0};
const int dy[4]={0,1,0,-1};
struct Lux
{
int k,x,y;
Lux(int a,int b,int c):k(a),x(b),y(c){}
Lux(){}
};
int map[N][N],id[N][N],cnt;
int n,p,A,B,C;
int dist[K][N][N];
bool in[K][N][N];
Lux s,t;
int spfa()
{
int i,vx,vy,fee,fee2;
queue<Lux>q;
memset(dist,0x3f,sizeof(dist));
dist[s.k][s.x][s.y]=0;
in[s.k][s.x][s.y]=1;
q.push(s);
while(!q.empty())
{
Lux U=q.front();q.pop();in[U.k][U.x][U.y]=0;
if(!U.k)continue;//没油了还跑什么
for(fee=i=0;i<4;i++)
{
vx=U.x+dx[i];
vy=U.y+dy[i];
if(i==2)fee=B;/*往回走要多付的费用在这里处理了。*/
if(!id[vx][vy])continue;
if(!map[vx][vy])
{
fee2=C;/*新开油站,准确的说这里的思想是把全图都开成加油站,原加油站强制加油,新加油站不强制,但加油要多付钱*/
if(U.k&&dist[U.k-1][vx][vy]>dist[U.k][U.x][U.y]+fee)
{/*因为加油站强制加油,所以不是加油站才能这么转移。*/
dist[U.k-1][vx][vy]=dist[U.k][U.x][U.y]+fee;
if(!in[U.k-1][vx][vy])in[U.k-1][vx][vy]=1,q.push(Lux(U.k-1,vx,vy));
}
}
else fee2=0;/*已经有原加油站了就不需要再付额外费用了*/
if(dist[p][vx][vy]>dist[U.k][U.x][U.y]+A+fee+fee2)
{/*加油的转移*/
dist[p][vx][vy]=dist[U.k][U.x][U.y]+A+fee+fee2;
if(!in[p][vx][vy])in[p][vx][vy]=1,q.push(Lux(p,vx,vy));
}
}
}
int ret=inf;
for(i=0;i<=p;i++)ret=min(ret,dist[i][t.x][t.y]);
return ret;
}
int main()
{
// freopen("test.in","r",stdin);
scanf("%d%d%d%d%d",&n,&p,&A,&B,&C);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&map[i][j]),id[i][j]=++cnt;
s=Lux(p,1,1),t=Lux(0,n,n);
printf("%d\n",spfa());
return 0;
}