[网络流24题-15] 汽车加油行驶 - 分层图

来源:互联网 发布:淘宝电脑配置高价格低 编辑:程序博客网 时间:2024/04/29 20:13

题目描述

给定一个 N*N 的方形网格,设其左上角为起点◎,坐标为(1,1),X 轴向右为正,Y轴向下为正,每个方格边长为1,如图所示。一辆汽车从起点◎出发驶向右下角终点▲,其坐标为(N,N) 。在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:
  (1)汽车只能沿网格边行驶,装满油后能行驶 K 条网格边。出发时汽车已装满油,在起点与终点处不设油库。
  (2)汽车经过一条网格边时,若其X 坐标或Y 坐标减小,则应付费用B,否则免付费用。
  (3)汽车在行驶过程中遇油库则应加满油并付加油费用A。
  (4)在需要时可在网格点处增设油库,并付增设油库费用C(不含加油费用A)。
  (5)(1)~(4)中的各数N、K、A、B、C均为正整数,且满足约束:2<=N <=100,2 <=K <= 10。
  设计一个算法,求出汽车从起点出发到达终点的一条所付费用最少的行驶路线。

  对于给定的交通网格,计算汽车从起点出发到达终点的一条所付费用最少的行驶路线。


输入格式

由文件input.txt提供输入数据。文件的第一行是 N,K,A,B,C的值。第二行起是一个 N*N 的 0-1 方阵,每行 N 个值,至 N+1 行结束。方阵的第 i 行第 j 列处的值为 1 表示在网格交叉点(i,j)处设置了一个油库,为0 时表示未设油库。各行相邻两个数以空格分隔。


输出格式

程序运行结束时,将最小费用输出到文件output.txt中。


样例数据

样例输入

9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0

样例输出

12


题目分析

这题比上题[网络流24题-14] 孤岛营救 - 分层图 简单那么一点点,啧啧啧。
一般使用分层图的特点是有一维比较小,并且去掉限制条件是标准的图论模型,于是按照比较小的那一维分层。
此题就是按照油量分层,建图如下:
1.若当前点是加油站,从当前点当前油量连接一条跨维边至此点满油量,边权为a
2.若当前点不是加油点,且已无油,从当前点连接一条跨维边至此点满油量,边权为a+c(c不包含加油费用)
3.从每个加油点连接一条跨维边至周围四点油量-1处,若横坐标或纵坐标减少,则边权为b,否则边权为0
4.从每个非加油点枚举油量连接一条跨维边至周围四点油量-1处,若横坐标或纵坐标减少,则边权为b,否则边权为0


源代码

#include<algorithm>#include<iostream>#include<iomanip>#include<cstring>#include<cstdlib>#include<vector>#include<cstdio>#include<cmath>#include<queue>using namespace std;inline const int Get_Int() {    int num=0,bj=1;    char x=getchar();    while(x<'0'||x>'9') {        if(x=='-')bj=-1;        x=getchar();    }    while(x>='0'&&x<='9') {        num=num*10+x-'0';        x=getchar();    }    return num*bj;}const int maxn=200005; //数组范围struct Edge { //前向星    int from,to,dist;};struct HeapNode {    int d,u; //u为当前结点    bool operator < (HeapNode a) const {        return d>a.d;    }};struct Dijkstra {    int n,m;    vector<Edge> edges; //邻接表    vector<int> G[maxn]; //记录每个结点可以到达的结点    bool vst[maxn];    int dist[maxn];    void init(int n) {        this->n=n;        for(int i=1; i<=n; i++)G[i].clear();        edges.clear();    }    void AddEdge(int from,int to,int dist) {        edges.push_back((Edge) {            from,to,dist        });        m=edges.size();        G[from].push_back(m-1);    }    void main(int s) { //核心算法        priority_queue<HeapNode> Q;        for(int i=1; i<=n; i++)dist[i]=0x7fffffff/2;        dist[s]=0;        memset(vst,0,sizeof(vst));        Q.push((HeapNode) {            0,s        });        while(!Q.empty()) {            HeapNode Now=Q.top();            Q.pop();            if(vst[Now.u])continue;            vst[Now.u]=1;            for(int i=0; i<G[Now.u].size(); i++) {                Edge& e=edges[G[Now.u][i]]; //边的信息                int Next=e.to;                if(dist[Next]>dist[Now.u]+e.dist) {                    dist[Next]=dist[Now.u]+e.dist;                    Q.push((HeapNode) {                        dist[Next],Next                    });                }            }        }    }} ;Dijkstra dij;int n,Gasoline,a,b,c,map[205][205],ans=0x7fffffff;int GetPos(int x,int y) { //二维坐标     return (x-1)*n+y;}int GetPos(int Gas,int x,int y) { //三维坐标     return (Gasoline-Gas)*n*n+GetPos(x,y);}void Build_Graph() { //按照油量分层     dij.init(n*n*(Gasoline+1));    for(int Gas=0; Gas<Gasoline; Gas++) { //油量         for(int i=1; i<=n; i++)            for(int j=1; j<=n; j++)                if(map[i][j])dij.AddEdge(GetPos(Gas,i,j),GetPos(Gasoline,i,j),a); //有加油站,向满油层连跨维边                 else if(Gas==0)dij.AddEdge(GetPos(Gas,i,j),GetPos(Gasoline,i,j),a+c); //无加油站,向满油层连跨维边     }    const int Dirx[]= {0,1,0,-1,0},Diry[]= {0,0,1,0,-1};    for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)            for(int k=1; k<=4; k++) {                int Nextx=i+Dirx[k],Nexty=j+Diry[k];                if(Nextx<1||Nextx>n||Nexty<1||Nexty>n)continue;                if(map[i][j]) { //此处是加油站,从满油层连出跨维边                     int Now=GetPos(Gasoline,i,j),Next=GetPos(Gasoline-1,Nextx,Nexty);                    if(k==3||k==4)dij.AddEdge(Now,Next,b); //倒着走                    else dij.AddEdge(Now,Next,0);                } else {                    for(int Gas=1; Gas<=Gasoline; Gas++) {                        int Now=GetPos(Gas,i,j),Next=GetPos(Gas-1,Nextx,Nexty);                        if(k==3||k==4)dij.AddEdge(Now,Next,b); //倒着走                        else dij.AddEdge(Now,Next,0);                    }                }            }}int main() {    n=Get_Int();    Gasoline=Get_Int();    a=Get_Int();    b=Get_Int();    c=Get_Int();    for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)map[i][j]=Get_Int();    Build_Graph();    int Start=GetPos(Gasoline,1,1);    dij.main(Start);    for(int i=0; i<=Gasoline; i++)ans=min(ans,dij.dist[GetPos(i,n,n)]);    printf("%d\n",ans);    return 0;}

0 1
原创粉丝点击