【网络流24题】汽车加油行驶问题 题解

题目传送门

题目大意: 有一张网格图,起点为 ( 1 , 1 ) (1,1) (1,1),终点为 ( n , n ) (n,n) (n,n),汽车满油时可以走 k k k 步,每步只能沿着网格边走,如果走到加油站则必须加满油,费用为 A A A,你也可以在任意地方新建一个加油站,费用为 C C C,走的过程中,如果 x x x y y y 坐标减小了那么需要付出 B B B 的费用,求出起点到终点的最小费用。

题解

众所周知,网络流24题中出现一些最短路题是很正常的。

k k k 步这个限制可以通过分层图解决,建 k + 1 k+1 k+1 层,每层对应当前还能走多少步,然后向上下左右走的边都从当前点向下一层建。

如果走到加油站,则强制这个点走到最高层(即加满油,能走的步数为 k k k),然后加上 A A A 的费用。要注意的是,如果此时已经在最高层,说明已经加过油了,就不需要了。

新建加油站的话就判断一下 当前位置是否能更新最高层中的对应位置 即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200010

int n,k,A,B,C,a[110][110];
struct edge{int y,z,next;};
edge e[maxn<<3];
int first[maxn],len=0;
void buildroad(int x,int y,int z)
{
	e[++len]=(edge){y,z,first[x]};
	first[x]=len;
}
int pos(int x,int y){return (x-1)*n+y;}
bool oil[maxn],v[maxn];
int q[maxn],st=1,ed=2,f[maxn],ans=2147483640;
int f1[4]={-1,0,1,0};
int f2[4]={0,-1,0,1};

int main()
{
	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",&a[i][j]);
		if(a[i][j])for(int c=0;c<=k;c++)oil[pos(i,j)+c*n*n]=true;
		int limit=(1-a[i][j])*(k-1);
		for(int c=0;c<=limit;c++)
		for(int l=0;l<4;l++)
		{
			int x=i+f1[l],y=j+f2[l];
			if(x<1||x>n||y<1||y>n)continue;
			buildroad(pos(i,j)+c*n*n,pos(x,y)+(c+1)*n*n,l<2?B:0);
		}
	}
	memset(f,63,sizeof(f));
	q[st]=1;f[1]=0;v[1]=true;
	while(st!=ed)
	{
		int x=q[st++];v[x]=false;st=st>(k+1)*n*n?1:st;
		if(oil[x]&&x>n*n)
		{
			if(f[(x-1)%(n*n)+1]>f[x]+A)
			{
				f[(x-1)%(n*n)+1]=f[x]+A;
				if(!v[(x-1)%(n*n)+1])v[q[ed++]=(x-1)%(n*n)+1]=true,ed=ed>(k+1)*n*n?1:ed;
			}
			continue;
		}
		if(!oil[x]&&x>n*n)
		{
			if(f[(x-1)%(n*n)+1]>f[x]+A+C)
			{
				f[(x-1)%(n*n)+1]=f[x]+A+C;
				if(!v[(x-1)%(n*n)+1])v[q[ed++]=(x-1)%(n*n)+1]=true,ed=ed>(k+1)*n*n?1:ed;
			}
		}
		for(int i=first[x];i;i=e[i].next)
		{
			int y=e[i].y;
			if(f[y]>f[x]+e[i].z)
			{
				f[y]=f[x]+e[i].z;
				if(!v[y])v[q[ed++]=y]=true,ed=ed>(k+1)*n*n?1:ed;
			}
		}
	}
	for(int c=0;c<=k;c++)ans=min(ans,f[(c+1)*n*n]);
	printf("%d",ans);
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.问题描述 给定一个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均为正整数。 算法设计: 求汽车从起点出发到达终点的一条所付费用最少的行驶路线。 数据输入: 输入数据。第一行是N,K,A,B,C的值,2 <= N <= 100, 2 <= K <= 10。第二行起是一个N*N 的0-1方阵,每行N 个值,至N+1行结束。方阵的第i 行第j 列处的值为1 表示在网格交叉点(i,j)处设置了一个油库,为0 时表示未设油库。 各行相邻的2 个数以空格分隔。 结果输出: 将找到的最优行驶路线所需的费用,即最小费用输出. Sample input 9 3 2 3 6 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 Sample output 12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值