洛谷 P4009 汽车加油行驶问题 (分层图最短路)

link

题目要满足三个条件:
1:汽车经过一条网格边时,若其 X 坐标或 Y 坐标减小,则应付费用 B ,否则免付费用。

2:汽车在行驶过程中遇油库则应加满油并付加油费用 A。

3:在需要时可在网格点处增设油库,并付增设油库费用 C(不含加油费用A )。

4:汽车只能沿网格边行驶,装满油后能行驶 K 条网格边。

思路:这题是洛谷网络流24题里的,但是题解都是清一色的最短路哈哈。建图跑最短路。根据费用分层,因为装满油只能走k次,所以我们分为k+1层,第0层代表满油,第一层代表消耗了一单位油。

对于第一个条件:我们在这层连一条有向边到上一层跟他相邻的四个方向,如果x或者y坐标减少,边权为b,否则边权为0。

对于第二个条件:因为遇到油库就强制必须加油,所以,对于第一层及其以上的层连接一条边到第一层,边权为A,此时还需要连接第0层与第一层,但是不要连接其他层,这是因为,如果经过这个点,他下一步只可能是第一层,不可能是其他层。

对于第三个条件:如果这个点不是油库,每一层都连一条边到第一层,边权为a+c,代表在这个点新建了一个油库。

第四个条件:建分层图

#include <bits/stdc++.h>
#define ll long long
#define pi pair<int,int>
#define mk make_pair
#define pb push_back
using namespace std;

const int maxn = 1e6+10;
int d[maxn],vis[maxn],n;
vector<pi>G[maxn];

int id(int x,int y,int k)
{
    
    
	return n*n*k + ((x-1)*n) + y;
}
void add(int u,int v,int w)
{
    
    
	G[u].pb(mk(v,w));
}

void dij(int s)
{
    
    
	priority_queue<pi>q;
	memset(d,0x3f,sizeof(d));
	d[s] = 0;
	q.push(mk(0,s));
	while(q.size())
	{
    
    
		int u = q.top().second;
		q.pop();
		if(vis[u])continue;
		vis[u] = 1;
		for(int i=0;i<G[u].size();i++)
		{
    
    
			int v = G[u][i].first;
			int w = G[u][i].second;
			if(d[v] > d[u] + w)
			{
    
    
				d[v] = d[u] + w;
				q.push(mk(-d[v],v));
			}
		}
	}
}
int main()
{
    
    
	int k,a,b,c;
	scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);
	for(int x=1;x<=n;x++)
	for(int y=1;y<=n;y++)
	{
    
    
		int ddd;
		scanf("%d",&ddd);
		if(ddd == 1)
		{
    
    
			for(int i=1;i<=k;i++) {
    
    
				add(id(x,y,i) , id(x,y,0) , a);
			}
			if(x+1 <= n) add(id(x, y, 0), id(x+1, y, 1), 0);
			if(x-1 >= 1) add(id(x, y, 0), id(x-1, y, 1), b);
			if(y+1 <= n) add(id(x, y, 0), id(x, y+1, 1), 0);
			if(y-1 >= 1) add(id(x, y, 0), id(x, y-1, 1), b);
		}
		else
		{
    
    
			for(int i=1;i<=k;i++)
			{
    
    
				add(id(x,y,k), id(x,y,0), a+c);
				if(x+1 <= n) add(id(x, y, i-1), id(x+1, y, i), 0);
				if(x-1 >= 1) add(id(x, y, i-1), id(x-1, y, i), b);
				if(y+1 <= n) add(id(x, y, i-1), id(x, y+1, i), 0);
				if(y-1 >= 1) add(id(x, y, i-1), id(x, y-1, i), b);
			}
		}
	}
	int s = id(1,1,0);
	dij(s);
	int ans = 0x3f3f3f3f;
	for(int i=0;i<=k;i++)ans = min(ans , d[id(n,n,i)]);
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44499508/article/details/107207778