日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷 - P4009 汽车加油行驶问题(分层图最短路/最小费用最大流)

發布時間:2024/4/11 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷 - P4009 汽车加油行驶问题(分层图最短路/最小费用最大流) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一個n*n的矩陣表示道路,途中有一些加油站,現在要從點(1,1)到達點(n,n),問最小花費,其中的一些規則如下:

  • 汽車只能沿著網格邊行駛,裝滿油后可以行駛K條邊,出發時已經裝滿油
  • 汽車經過一條網格邊時,若x或y減小,需要花費B元,其余情況沒有花費
  • 汽車在行駛過程中遇到油庫則必須強制加滿油,并花費A元
  • 在需要時可以在網格點增設臨時油庫,并支付花費C元(不包括加油的A元)
  • N,K,A,B,C均為正整數,且滿足2<=N<=100,2<=K<=10
  • 輸出從起點到達終點的最小費用

    題目分析:又是條件冗雜的一道題目,不過是一個比較明顯的分層圖問題,又是要求最小花費,我們可以直接涉及一個動態規劃的轉移方程,然后用spfa迭代更新就好了,這個一會直接掛個代碼就行了,因為最短路寫起來比較簡單也比較好理解

    然后重點說一下怎么用費用流求解吧,因為這個題目是要求最小花費,所以建好圖后直接跑費用流也是可行的,關于建圖,我們也可以直接建分層圖,首先拋去油箱與加油站的情況,如果只是要求從起點到終點的最短路,那么我們直接在一層中進行連邊,源點連向起點,流量為1,花費為0,然后按照上面的條件2連邊,最后讓終點連向匯點就好了,至于多出來的油箱限制,我們可以將每一種情況視為新的一層,我選擇的是將k拆為k層圖,每一層圖代表當前油箱剩余的油還有多少,那么在轉移的時候,符合條件的連邊就可以直接從(x,y,k)連邊到(xx,yy,k-1)了,對于每個油庫,因為是強制滿油,所以我們可以將該點[0,k-1]層的點都向第k層的點連邊,花費為a,只有第k層才能向四周連邊,而對于非油庫的點,最優解肯定是當油箱空了的時候才建立臨時油庫,所以只需要讓第0層的該點向第k層建邊,花費為a+c就好了,具體細節還真就沒有了,主要還是在代碼實現的過程中一定要細心細心再細心,一開始建邊的時候因為小于等于漏了一個等于號,調了20多分鐘。。太菜了:

    三維點表示的是(x,y,k),x,y代表坐標,k代表層數

  • 源點->(1,1,k),流量為1,花費為0
  • (x,y,k)->(xx,yy,k-1),流量為無窮大,花費符合條件2
  • 當前點是否為油庫:
  • 是油庫:(x,y,t)t∈[0,k-1]->(x,y,k),流量為無窮大,花費為a
  • 不是油庫:(x,y,0)->(x,y,k),流量為無窮大,花費為a+c
  • (n,n,t)t∈[0,k]->匯點,流量為無窮大,花費為0
  • 關于費用流的建圖就到此為止了,按照上述要求建好圖后直接跑最小費用最大流就是答案了

    代碼:

    最小費用最大流:

    #include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e5+100;//點const int M=1e6+100;//邊const int bb[4][2]={0,1,0,-1,1,0,-1,0};struct Edge {int to,w,cost,next; }edge[M];int head[N],cnt;void addedge(int u,int v,int w,int cost) {edge[cnt].to=v;edge[cnt].w=w;edge[cnt].cost=cost;edge[cnt].next=head[u];head[u]=cnt++;edge[cnt].to=u;edge[cnt].w=0;edge[cnt].cost=-cost;edge[cnt].next=head[v];head[v]=cnt++; }int d[N],incf[N],pre[N],n;bool vis[N];bool spfa(int s,int t) {memset(d,inf,sizeof(d));memset(vis,false,sizeof(vis));memset(pre,-1,sizeof(pre));queue<int>q;q.push(s);vis[s]=true;incf[s]=inf;d[s]=0;while(!q.empty()){int u=q.front();q.pop();vis[u]=false;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;int cost=edge[i].cost;if(!w)continue;if(d[v]>d[u]+cost){d[v]=d[u]+cost;pre[v]=i;incf[v]=min(incf[u],w);if(!vis[v]){vis[v]=true;q.push(v);}}}}return pre[t]!=-1; }int update(int s,int t) {int x=t;while(x!=s){int i=pre[x];edge[i].w-=incf[t];edge[i^1].w+=incf[t];x=edge[i^1].to;}return d[t]*incf[t]; }void init() {memset(head,-1,sizeof(head));cnt=0; }int solve(int st,int ed) {int ans=0;while(spfa(st,ed))ans+=update(st,ed);return ans; }int get_id(int x,int y,int k)//第k層的(x,y) {return (x-1)*n+y+k*n*n; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);init();int k,a,b,c,st=N-1,ed=st-1;scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);addedge(st,get_id(1,1,k),1,0);//源點->(1,1,k) for(int i=0;i<=k;i++)//(n,n,kk)kk∈[0,k]->匯點 addedge(get_id(n,n,i),ed,inf,0);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){int val;scanf("%d",&val);if(val)//強制加油{for(int t=0;t<k;t++)//(i,j,kk)kk∈[0,k-1]->(i,j,k) addedge(get_id(i,j,t),get_id(i,j,k),inf,a);for(int t=0;t<4;t++)//(i,j,k)->(xx,yy,k-1) {int xx=i+bb[t][0];int yy=j+bb[t][1];if(xx<=0||yy<=0||xx>n||yy>n)continue;int len=0;if(xx<i||yy<j)len=b;addedge(get_id(i,j,k),get_id(xx,yy,k-1),inf,len);}} else{for(int t=0;t<4;t++){int xx=i+bb[t][0];int yy=j+bb[t][1];if(xx<=0||yy<=0||xx>n||yy>n)continue;int len=0;if(xx<i||yy<j)len=b;for(int kk=1;kk<=k;kk++)addedge(get_id(i,j,kk),get_id(xx,yy,kk-1),inf,len);}addedge(get_id(i,j,0),get_id(i,j,k),inf,a+c);}}printf("%d\n",solve(st,ed));return 0; }

    分層圖最短路(spfa):

    #include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=110;const int bb[4][2]={0,1,0,-1,1,0,-1,0};int maze[N][N],d[N][N][15],n,K,a,b,c;bool vis[N][N][15];struct Node {int x,y,k;Node(int X,int Y,int K){x=X;y=Y;k=K;} };void spfa() {memset(vis,false,sizeof(vis));memset(d,inf,sizeof(d));queue<Node>q;q.push(Node(1,1,K));vis[1][1][K]=true;d[1][1][K]=0;while(q.size()){Node cur=q.front();q.pop();int x=cur.x;int y=cur.y;int k=cur.k;vis[x][y][k]=false;if(k<K)//加油{if(maze[x][y])//有加油站{if(d[x][y][K]>d[x][y][k]+a){d[x][y][K]=d[x][y][k]+a;if(!vis[x][y][K]){vis[x][y][K]=true;q.push(Node(x,y,K));}}continue;//強制加油}else//沒加油站 {if(d[x][y][K]>d[x][y][k]+a+c){d[x][y][K]=d[x][y][k]+a+c;if(!vis[x][y][K]){vis[x][y][K]=true;q.push(Node(x,y,K));}}} } if(k)//跑路{for(int i=0;i<4;i++){int xx=x+bb[i][0];int yy=y+bb[i][1];if(xx<=0||yy<=0||xx>n||yy>n)continue;int len=0;if(xx<x||yy<y)len=b;if(d[xx][yy][k-1]>d[x][y][k]+len){d[xx][yy][k-1]=d[x][y][k]+len;if(!vis[xx][yy][k-1]){vis[xx][yy][k-1]=true;q.push(Node(xx,yy,k-1));}}}} } }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);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",&maze[i][j]);spfa();int ans=inf;for(int i=0;i<=K;i++)ans=min(ans,d[n][n][i]);printf("%d\n",ans);return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的洛谷 - P4009 汽车加油行驶问题(分层图最短路/最小费用最大流)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。