1. 程式人生 > >汽車加油行駛問題(BFS/SPFA思想)

汽車加油行駛問題(BFS/SPFA思想)

原題見洛谷

分析

雖然題目標籤打的是網路流24題,但這題可以用BFS加上一點點優化高效通過。

觀察資料範圍,N最大100,K最大11,答案不確定,於是設一個ans[101][101][11]表示走到(x,y)時剩餘的油為rest時最優解。 開一個mp[101][101]存加油站的資訊。有以下幾個注意的地方,按程式碼裡的順序來。

1,當前取出的節點,如果對應的ans比當前最優解大,直接跳過。

2,確定下一個點後,如果到了終點,先更新當前最優解。 

3,先判斷到的點是不是有加油站以及油是否滿了。

4,如果沒有加油站且到這個點後油剩0,再臨時建一個加油站,且這個站對後面無影響(肯定不會回到這個點啦)。

5,如果此時的答案比最優解大,跳過。

6,如果此時的答案比這個點的ans好,更新這個點的ans,如果沒在佇列裡就入隊。

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int N,K,A,B,C,in_q[101][101][11],ans[101][101][11],mp[101][101],dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
struct data{int x,y,rest;}; queue<data>q;

int BFS()
{	
	data t;
	int i,j,k,now_x,now_y,now_rest,now_cost,t_x,t_y,t_rest,t_cost,now_min=INF; //t_表示下一格的,now_表示隊首節點的 
	for(i=0;i<=N;i++) 
	for(j=0;j<=N;j++) 
	for(k=0;k<=K;k++) 
		ans[i][j][k]=INF;
	q.push((data){1,1,K}); ans[1][1][K]=0; in_q[1][1][K]=1; //起點為0 
	while(!q.empty())
	{
		t=q.front(); q.pop();
		now_x=t.x,now_y=t.y,now_rest=t.rest,now_cost=ans[now_x][now_y][now_rest];
		in_q[now_x][now_y][now_rest]=0; //出隊了 
		
		if(now_cost>now_min) continue; //比當前最優還大,跳過 
		
		for(i=0;i<=3;i++)
		{
			t_x=now_x+dx[i];t_y=now_y+dy[i];
			if(t_x<1||t_x>N||t_y<1||t_y>N) continue; //越界 
			
			t_cost=now_cost; t_rest=now_rest-1; //走一格要減一 
			
			if(dx[i]==-1||dy[i]==-1) t_cost+=B;  //反走了,加錢 
			
			if(t_x==N&&t_y==N) now_min=min(now_min,t_cost); //先更新當前最優值 
			
			if(mp[t_x][t_y]&&t_rest!=K) //油未滿,且到了加油站,強制消費... 
			{
				t_cost+=A;
				t_rest=K;
			}
	
			if(t_rest==0)  //沒有加油站,油又耗完了,如果有加油站的話上一個if後,rest肯定已經不是0了 
			{
				t_cost+=A+C;  //可以想見,以後絕對不會倒回來再加一次了 
				t_rest=K;
			}
			
			if(now_min<t_cost) continue; //如果比最優值還大,不用走了 
			
			if(ans[t_x][t_y][t_rest]>t_cost) //答案更優 
			{
				ans[t_x][t_y][t_rest]=t_cost; //先修改 
				if(!in_q[t_x][t_y][t_rest]) //不在佇列裡就加入 
				{
					q.push((data){t_x,t_y,t_rest});
					in_q[t_x][t_y][t_rest]=1;
				}
			}
		}
	}
	return now_min;
}

int main()
{
	cin>>N>>K>>A>>B>>C;
	for(int i=1;i<=N;i++)
	for(int j=1;j<=N;j++)
		cin>>mp[i][j];
	cout<<BFS(); return 0;
}