Luogu P4009 자동차 급유 문제 (계층 맵에서 최단 경로)

링크

질문은 다음 세 가지 조건을 충족해야합니다.
1 : 자동차가 그리드 가장자리를 통과 할 때 X 좌표 또는 Y 좌표가 감소하면 수수료 B를 지불해야하며 그렇지 않으면 수수료가 무료입니다.

2 : 차량이 주행 중 오일 디포를 만났을 때, 충전하고 주 유료 A를 지불해야합니다.

3 : 필요할 때 그리드 지점에 오일 디포를 추가하고 추가 오일 디포 비용 C (급유 비용 A 제외)를 지불 할 수 있습니다.

4 : 자동차는 그리드의 가장자리를 따라서 만 운전할 수 있으며 연료로 채워진 후 K 그리드 가장자리를 운전할 수 있습니다.

아이디어 :이 질문은 Luogu Network Stream 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