【线性规划与网络流24题 15】汽车加油

给个负责任的OJ:汽车加油


Description

给定一个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

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

Output

程序运行结束时,将最小费用输出

Sample Input

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

Sample Output

12


这个题,完全不像是网络流的类型啊,然后一看就不会写

学了题解之后,发现图论的很多思路和动态规划也是一样一样的,和搜索也是一样的

在(x,y)二维表示坐标,状态表示不够全面的时候,往往在加一维来表示


所以,本题是一个最短路问题

状态的表示量为(i,j,k),其中(i,j)为坐标,k为当前在该格子中的剩余的油量

然后,根据题中的数据来添加状态转移的边和权值


推荐一篇博客:

http://blog.csdn.net/willinglive/article/details/38148805


这个题,还有1个坑点,在于我们需要对maxn的值进行计算

n最大是100,那么maxn是多少?

算大了无所谓(只要不开得过大,超过题目中所给的最大空间)

算小了会是莫名其妙的wa

有可能的达到的范围是:100*100*100

那么需要1e6的数组来保存每个节点的能到的最小值


代码如下:

用SPFA算法跑的最短路,大概复杂度是O(nlogn),是基本可以AC的


#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6+500;
const int maxe=2e6+500;
const int maxsize=1e6+500;
const int INF=1<<30;

struct Edge{
    int u,w,v,nxt;
}edge[maxe];
int cnt,q[maxsize];
int mp[110][110];
int a,b,c,k,n,s,t;
int C[2]={0,0};
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};

int getpoint(int k,int x,int y){
    return k*n*n+x*n+y;
}

int Head[maxn],d[maxn];
bool vis[maxn];

void addedge(int u,int v,int w){
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nxt=Head[u];
    Head[u]=cnt++;
}

void SPFA(){
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=t;i++) d[i]=INF;
    d[s]=0;
    vis[s]=true;
    int l=0,r=0;
    q[r++]=s;
    while(l<r){
        int u=q[l%maxsize];
        l++;
        vis[u]=0;
        for(int i=Head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].v;
            if (edge[i].w+d[u]<d[v]){
                d[v]=edge[i].w+d[u];
                if (!vis[v]){
                    vis[v]=1;
                    q[r%maxsize]=v;
                    r++;
                }
            }
        }
    }
    return;
}

int main(){
    freopen("input.txt","r",stdin);
    while(scanf("%d%d%d%d%d",&n,&k,&a,&b,&c)!=EOF){
        //cout<<n<<" "<<k<<endl;
        s=getpoint(k,1,1);
        t=getpoint(k,n,n);
        C[0]=c;C[1]=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&mp[i][j]);
        memset(Head,-1,sizeof(Head));
        cnt=0;
        for(int l=0;l<=k;l++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            int temp=getpoint(l,i,j);
            if (l==0) addedge(temp,getpoint(k,i,j),a+C[mp[i][j]]);
            //走不动了,油量不够了,只能在原地加油
            //原地加油分成两种情况,有油库和没有油库
            else{
                for(int dir=0;dir<4;dir++){
                    int x=i+dx[dir],y=j+dy[dir];
                    if (x>=1&&x<=n&&y>=1&&y<=n){
                        if (dir<=1){
                            if (mp[x][y]) addedge(temp,getpoint(k,x,y),b+a);
                            else addedge(temp,getpoint(l-1,x,y),b);
                            //往左上走,位置变了
                            //有油库我们就可以选择加油
                        }
                        else{
                            if (mp[x][y]) addedge(temp,getpoint(k,x,y),a);
                            else addedge(temp,getpoint(l-1,x,y),0);
                            //往右下走,位置变了
                            //有油库我们就可以选择加油
                        }
                    }
                }
            }
            if (l!=k) addedge(temp,getpoint(k,i,j),a+C[mp[i][j]]);
            //如果油箱不满,也可以加油
        }
        SPFA();
        int ans=INF;
        for(int l=0;l<=k;l++)
            if (d[getpoint(l,n,n)]<ans)
                ans=d[getpoint(l,n,n)];
        cout<<ans<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.问描述 给定一个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均为正整数。 算法设计: 求汽车从起点出发到达终点的一条所付费用最少的行驶路线。 数据输入: 输入数据。第一行是N,K,A,B,C的值,2 <= N <= 100, 2 <= K <= 10。第二行起是一个N*N 的0-1方阵,每行N 个值,至N+1行结束。方阵的第i 行第j 列处的值为1 表示在网格交叉点(i,j)处设置了一个油库,为0 时表示未设油库。 各行相邻的2 个数以空格分隔。 结果输出: 将找到的最优行驶路线所需的费用,即最小费用输出. Sample input 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 Sample output 12
Problem D:汽车最少费用加油行驶 Description 给定一个 N*N 的方形网格, 设其左上角坐标为 (1, 1), X 轴向右为正, Y 轴向下为正, 每个方格边长为 1, 右下角坐标为 (N, N). 一辆已装满油的汽车从 (1, 1) 为起点出发驶向终点 (N, N). 在若干个网格交叉点处设有油库供汽车在行驶途中加油, 在起点与终点处不设油库. 汽车在行驶过程中遵守如下规则: 1. 只能沿网格边行驶, 装满油后能行驶 K 条网格边 2. 当行驶经过一条网格边时, 若其 X 坐标或 Y 坐标减小, 则应付费用 B, 否则免付费用 3. 在行驶过程中遇油库则应加满油并付加油费用 A 4. 在需要时可在网格点处增设油库, 并付增设油库费用 C (不含加油费用A) 上述各数中的 N, K, A, B, C 均为正整数. 求汽车从起点出发到达终点的一条所付费用最少的行驶路线所需要的费用. Input 输入数据的第一行是 N, K, A, B, C 的值, 2 ≤ N ≤ 100, 2 ≤ K ≤ 10. 第二行起是一个 N*N 的 0-1 方阵, 每行 N 个值, 至 N+1 行结束. 方阵的第 i 行第 j 列处的值为 1 表示在网格交叉点 (i, j) 处设置有一个油库, 为 0 时表示未设有油库. 各行相邻的两个数以空格分隔. Output 对于测试用例的输入数据, 在一行上输出最优行驶路线所需的费用, 即最小费用. Sample Input 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 Sample Output 12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值