汽車加油行駛問題(BFS/SPFA思想)
阿新 • • 發佈:2019-02-02
原題見洛谷
分析
雖然題目標籤打的是網路流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; }