汽车加油行驶问题

dante264 2008-11-25 11:39:05
这是题目原题
给定一个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均为正整数。


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 时表示未设油库。各行相邻的2 个数以空格分隔。


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

这个问题如果用动态规划法解决的化,我碰到了一个实现的难点(不知道是否由于算法思路的问题)
如果我们自顶向下从点(n,n)向后推的话,那就需要这一点上“剩余的K”的值,而要命的是“余K”值是随不同的递归分支而不同的,而产生递归分支之前我们就要根据“余K”值是否为0的情况来判断比如(是否要建立加油站来加油等等),此时“余K”值由于缺乏分支探底根本就没有产生!这样不就矛盾了吗?
请高手释疑,或者告诉我具体的实现代码,我已经看过一些模糊的思想,但似乎都没有绕开我说的这个矛盾,难道他们自底向上的?
谢谢!
我的Email ouyangkang@gmail.com

...全文
2237 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
OSJake 2009-10-09
  • 打赏
  • 举报
回复
楼上的把递归实现代码发出来看看..........
love_jk 2009-07-08
  • 打赏
  • 举报
回复
采用的是动态规划的思想来解题,用备忘录的方法进行递归,与Dijstra算法计算最短路径的思想相似,其实可以求出任意一点的最少油费值,向四个方向检测,子节点询问父节点,由于子的费用大于等于父的费用,所有不存在死循环。
下面是我递归计算的每一坐标点的费用值,
0 0 0 8 10 10 10 15 0
0 0 7 9 9 11 12 12 12
2 2 4 4 4 11 11 13 0
2 2 4 4 9 11 11 11 13
4 4 4 6 6 6 8 8 8
4 6 6 6 6 11 8 10 10
4 6 6 6 8 8 8 10 12
6 6 6 8 8 8 15 12 12
6 8 8 8 8 16 15 12 12
由该费用值表可以看出,最后的解为:cost[n-1][n-1]=12
h547758424 2009-06-10
  • 打赏
  • 举报
回复
问一下你用的是什么方法?不是动态规划吗?
h547758424 2009-05-30
  • 打赏
  • 举报
回复
谁有更简单点的啊,我也在做这个题
asdf0808 2009-05-16
  • 打赏
  • 举报
回复
其实不会死循环的,只要另设一个二位数组保存已询问过的结点就行,因为一个点不可能重覆走两次的,如果一个点重复走了两次,那么这种方法不可能是最优的
asdf0808 2009-05-16
  • 打赏
  • 举报
回复
动态规划时什么样的值才是最优的?很明显,如果到达i,j结点有两种方法,一种花费小而剩余k值也小,另一种花费多但剩余k值也大,那么该选那种?如果选择花费少的,那么剩余k值很可能走不到下一个加油站,而支付昂贵的建库费用;如果选择k值大的,那可能花费太多或者根本不需要这么大的k值。到底如何衡量?
「已注销」 2008-12-25
  • 打赏
  • 举报
回复
这是不是太复杂了?
dante264 2008-12-22
  • 打赏
  • 举报
回复
这个问题我想复杂了,实际上“没有知道余K值"的顾虑是不存在的,由于动态规划实则是往下规划递归过程然后在往上层函数递交结果,那么我们可以吧“是否建立加油站”放在“往上层函数递交结果”这个步骤中,这样可以实现一个算法。
要命的是,该动态规划本身有问题,我们是往四个方向检测最优路径的,那们这会导致死循环,就是子节点询问父节点,父节点又询问子节点...
不过我还是寻觅到一种方法,这种方法是先建模,在用Dijstra算法计算最短路径,我已经实现了(结果应该是正确的):

#include<iostream.h>
#include<stdio.h>
#include<set>
#include<algorithm>
using namespace std;
int n,nn;
int k,a,b,c,i,j;

int numb (int i,int j){
return ((i-1)*n+j-1)*(k+2)+2;
}

//template<class T>
//基于邻接链表的加权有向图
class Node{
public:
int j;//边指向Vex[j]
int w;
Node * next;
Node(int j1,int w1,Node * n1);
};

Node::Node(int j1,int w1,Node * n1){
j=j1;
w=w1;
next=n1;
}

class Vex{
public:
Node * first;
Vex();
~Vex();
};

Vex::Vex(){
first=NULL;
}

Vex::~Vex(){
Node * e=first;
Node * temp;
while(e!=NULL){
temp=e->next;
delete e;
e = temp;
}
}

class LinkedWDigraph{
public:
LinkedWDigraph(int n);
~LinkedWDigraph();
void insert(int i,int j,int w);//插入边
void minpath();
private:
Vex * vexs;
int num;
};

LinkedWDigraph::LinkedWDigraph(int n){
vexs=new Vex[n];
num=n;
}

LinkedWDigraph::~LinkedWDigraph(){
delete [] vexs;
}

void LinkedWDigraph::insert(int i,int j,int w){
Node * a=new Node(j,w,vexs[i].first);
vexs[i].first=a;
}



void LinkedWDigraph::minpath(){
//从节点0开始,到节点1结束

set<pair<int,int> > s;
int * done=new int[num];//标记已经找到最短路径的节点
int i;
bool * doned=new bool[num];
for(i=1;i<num;i++){
done[i]=0x7fffffff;
doned[i]=false;
}
done[0]=0;
doned[0]=true;
Node * temp;
int ld=0;
//先对始节点0做处理
for(i=1;i<num;i++)
s.insert(pair<int,int>(0x7fffffff,i));
temp=vexs[0].first;
while(temp!=NULL){
s.erase(s.find(pair<int,int>(0x7fffffff,temp->j)));
s.insert(pair<int,int>(temp->w,temp->j));
done[temp->j]=temp->w;
temp=temp->next;
}
for(i=1;i<num;i++){
int temp2=s.begin()->first;
ld=s.begin()->second;
done[ld]=s.begin()->first;
doned[ld]=true;
temp=vexs[ld].first;
if(ld==1){
cout<<done[1];
delete [] done;
delete [] doned;
return;
}
s.erase(s.begin());
if(done[ld]==0x7fffffff)
continue;
while(temp!=NULL){
if(doned[temp->j]==false&&(temp->w+done[ld])<done[temp->j]){
s.erase(s.find(pair<int,int>(done[temp->j],temp->j)));
s.insert(pair<int,int>(temp->w+done[ld],temp->j));
done[temp->j]=temp->w+done[ld];
}
temp=temp->next;
}
}
//cout<<done[1];
delete [] done;
delete [] doned;
}

void constructMap(LinkedWDigraph & graph){
int ** oils=new int * [n];
for(i=0;i!=n;i++)
oils[i]=new int[n];
for(i=0;i!=n;i++)
for(j=0;j!=n;j++)
scanf("%d",oils[i]+j);
int k1,k2,i1,j1,cost;
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
k1=numb(i,j);
for(int e=1;e<=k;e++){
for(int d=0;d<4;d++){
i1=i+dir[d][0];
j1=j+dir[d][1];
if(i1>0&&i1<=n&&j1>0&&j1<=n){
cost=(d>1)?b:0;
k2=numb(i1,j1);
if(oils[i1-1][j1-1]==1)
graph.insert(k1+e,k2+k,cost+a);
else
graph.insert(k1+e,k2+e-1,cost);
}
}
}
if(oils[i-1][j-1]==0)
graph.insert(k1,k1+k+1,a+c);
graph.insert(k1+k+1,k1+k,0);
}

graph.insert(0,k+2,0);
k1=numb(n,n);
for(i=0;i<=k;i++)
graph.insert(k1+i,1,0);


for(i=0;i!=n;i++)
delete [] oils[i];

}

int main(){
scanf("%d",&n);scanf("%d",&k);scanf("%d",&a);
scanf("%d",&b);scanf("%d",&c);
//cin>>n>>k>>a>>b>>c;
nn=n*n*(k+2)+2;
LinkedWDigraph * g1= new LinkedWDigraph(nn);
constructMap(*g1);
g1->minpath();
return 0;
}
//谢谢大家
chanchen7 2008-12-18
  • 打赏
  • 举报
回复
郁闷死你老大我了
goziem 2008-12-01
  • 打赏
  • 举报
回复
帮顶一下
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

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧