关于最小代价路径的算法 各位请进

winthrop2009 2009-08-27 10:05:04
小生最近在做一个路径规划的程序 其中有这样一部分:

已知400*300的矩阵 对矩阵中每一个位置进行赋值 赋值范围为0-6 定义值越大可通过性越差
以最后一行的中间位置为起点 第一行的任一点为终点 也就是说从下往上走

现在该如何用VC算法实现找到最小代价路径的目的呢 谢谢各位 如何做的想法也行 最好能有示例代码 确定可行后所有分值奉上
...全文
476 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
firePhoenix1981 2009-08-28
  • 打赏
  • 举报
回复
这是堆的实现:
#ifndef __HEAP__
#define __HEAP__
#include"iostream"

using namespace std;

/*
implement a big-root heap
*/

typedef int (*cmp_func)(int index1, int index2);
typedef void (*swap_func)(int index1, int index2);

template<class T>
void adjust_sub_tree(T A[], int n, int root, cmp_func *cmp, swap_func *swap)
{
int left, right;
int i=root;/*root is the index, and n is the number*/
int max;

while(1)
{
left=(i*2+1 - (n-1))<=0?1:0;
right=(i*2+2 - (n-1))<=0?1:0;

if(left==1 || right==1)
{
max=i*2+1;
if(right==1)
{
if((*cmp)(i*2+1, i*2+2)<0)
{
max=i*2+2;
}
}
if((*cmp)(max, i)>0)// A[max]>A[i])
{
(*swap)(i, max);
i=max;
}
else
{
break;
}

}
else
{
break;
}
}
return;
}


template <class T>
void make_heap(T A[], int n, cmp_func cmp, swap_func swap)
{
/*n starts from 0, so i's (i>0) parent index should be (i-1)/2*/
/* j's (j>=0) children should be 2*j+1, 2*j+2 */
int p;

p=(n-1-1)/2; /*the last parent*/

while(p>=0)
{
adjust_sub_tree(A, n, p--, &cmp, &swap);
}

return;
}

template <class T>
T* pop_heap(T A[], int n, cmp_func cmp, swap_func swap)
{
if(n==1)
{
return &A[0];
}

/*at first, we swap A[0] and A[n-1]*/
(*swap)(0, n-1);

/*now, adjust the heap to be valid*/
adjust_sub_tree(A, n-1, 0, &cmp, &swap);

return &A[n-1];
}

#endif
firePhoenix1981 2009-08-28
  • 打赏
  • 举报
回复
贴一个实现:
#include "ostream"
#include "heap"

#define ROW 400
#define COL 300
#define MAX_OBSTACLE 6

typedef struct node
{
int bit_found; /*0->not valued, 1->have valid value, 2->has been found*/
int obstacle;
struct node * pre;
int shortest_dis;/*indicates the shortest distance to the original one*/
}NODE;/*this define is not very good, should seperate two kinds info*/

int not_found_num=ROW*COL; /*indicates the number not have been found*/

NODE map[ROW][COL];

NODE *heap[ROW*COL]={NULL};/*this is the heap, which stores all of the un-founded nodes*/
int heap_len=0;/*the valid number in the heap*/

int cmp(int index1, int index2)
{
return -(heap[index1]->shortest_dis-heap[index2]->shortest_dis); /*the template is a big-heap*/
}

void swap(int index1, int index2)
{
NODE *tmp = heap[index2];
heap[index2] = heap[index1];
heap[index1] = tmp;
return;
}

int find_new_node(int *pRow, int *pCol)
{
if(heap_len!=0)
{
NODE *pMin = *pop_heap(heap, heap_len, cmp, swap);
int offset = (pMin-(NODE *)map);
*pRow = offset/COL;
*pCol = offset%COL;
pMin->bit_found = 2;
heap_len --;
return 0;
}
return -1;
}

void update_distance(int new_row, int new_col)
{
/*update the distance of the nodes adhere to new node*/
/**/
#define UPDATE(row, col) \
{\
if( (map[row][col].shortest_dis>\
map[new_row][new_col].shortest_dis+map[row][col].obstacle)\
&&\
(map[row][col].bit_found != 2))\
{\
map[row][col].shortest_dis = \
map[new_row][new_col].shortest_dis+map[row][col].obstacle; \
map[row][col].pre = &map[new_row][new_col]; \
}\
}

#define INSERT_INTO_HEAP(row, col) \
{\
if(map[row][col].bit_found == 0)\
{\
heap[heap_len++] = &map[row][col];\
map[row][col].bit_found = 1;\
}\
}

/*add these node into heap if it has not been set valid value yet*/
if(new_row>0)
{
/*up is valid*/
UPDATE(new_row-1, new_col)
INSERT_INTO_HEAP(new_row-1, new_col)
}
if(new_row<ROW-1)
{
UPDATE(new_row+1, new_col)
INSERT_INTO_HEAP(new_row+1, new_col)
}
if(new_col>0)
{
UPDATE(new_row, new_col-1)
INSERT_INTO_HEAP(new_row, new_col-1)
}
if(new_col<COL-1)
{
UPDATE(new_row, new_col+1)
INSERT_INTO_HEAP(new_row, new_col+1)
}

/*now, we should modify the heap to the right format*/
make_heap(heap, heap_len, cmp, swap);
}



int find_shortest_path(int start_row, int start_col)
{
int new_row, new_col;/*saving the coordinate of the new node*/
//init the S set, done in the main initilization area

//if there are some nodes not been found, then go on
while(find_new_node(&new_row, &new_col) == 0)
{
//cout<<"reaching node: "<<new_row<<", "<<new_col<<endl;
if(new_row == 0)
{
/*reach the first row*/
return new_col;
}
update_distance(new_row, new_col);
}

return -1;
}

#include<stdlib.h>
#include<time.h>

inline void display_map()
{
int i, j;

for(i=0;i<ROW;i++)
{
for(j=0;j<COL;j++)
printf("%4d", map[i][j].obstacle);
printf("\n");
}
cout<<endl;
return;
}

int main(void)
{
int i,j;

/*use rand to init the vector*/
srand((unsigned int)time(NULL));
for(i=0;i<ROW;i++)
{
for(j=0;j<COL;j++)
{
double r=(double)rand();
map[i][j].obstacle = (int) ((r/(double)0xffffffff) * (double)(MAX_OBSTACLE+1));
map[i][j].bit_found = 0;
map[i][j].pre = NULL;
map[i][j].shortest_dis = 1000000; /*the unavialable value*/

}
}

//display_map();

i=ROW-1, j=COL/2;
map[i][j].shortest_dis = 0;
map[i][j].bit_found = 1;
heap[heap_len++] = &map[i][j];

j=find_shortest_path(i, j);

/*print the shortest path*/
cout<<endl;
i=0;
while(1)
{
NODE *tmp=map[i][j].pre;
cout<<i<<":"<<j<<" ";
if(map[i][j].pre==NULL)
break;
i=(tmp-(NODE*)map)/COL;
j=(tmp-(NODE*)map)%COL;
cout<<"<-";
}



return 0;
}
LeonTown 2009-08-27
  • 打赏
  • 举报
回复
学习
xiaoyu821120 2009-08-27
  • 打赏
  • 举报
回复
动归,只要记录下走到每一个位置最小的代价就可以了。在搜索过程中一行一行从下往上做迭代
shex4 2009-08-27
  • 打赏
  • 举报
回复
经典的动态规划吧。

不过楼主没说清楚怎么走。从上往下?应该能左下,右下吧
baihacker 2009-08-27
  • 打赏
  • 举报
回复
以第一行或者最后一行起点没有什么区别.
记sum(i, j, k)为第i行第j到k列的和.(或者k到j)
f(i, j)表示到达第i行j列可能的最小代价。
先在第一行中点,代价为f(1, t)
然后到第二行第i列,只可能是从第一行中点下来,然后左走或者右走到第i列
所以f(2, i) = f(1,t) + sum(2, i, t)
再看第三行i列,可以从f(2, 1)下来,然后从第三行1列走到第三行i列。代价为f(2, 1)加上sum(3, 1, i)
同样的可以是f(2, j) + sum(3, j, i)
在这样的值中取最小的,就是f(2, i)
这样就可以一层一层地推下去了。
直到最后一层。
(显然来回走是累死不讨好的,所以可以这样走)

和zoj monthly, Nov 2008在一定程序上有类似
E题目大意:100*100的格子,每个格子里有整数的分数。一个人从左上角走到右下角,每次可以往左、右或下走到相邻的格子,如果格子里是非正数,则每经过一次格子会加上那个格子里的分数,如果是格子里是正数,则第一次经过它是加分的,以后再经过这个格子都会减掉其中的分数,求到终点最大的得分方法。

解法:中等题。显然反复来回走是没什么好处的。我们可以把每一行单独dp,然后每一行的解是从上一行第k个格子直接下到本行第k个格子,然后假设最后停到第j个格子(j<k),则最优解可能是从k向右走到某个地方再回头向左经k走到j,再继续左走到某个地方再后头向右走回j。(j>k,j=k可以类似讨论)。

设下标从1开始。

首先,对于每一行,我们可以求出从第1格到第j格的权值和sum[j]。然后定义left[j]是从j向左走到某个格子再掉头回到j的最大值,right[j]表示从j向右走到某个格子再掉头回到j的最大的分。显然初始left[j]=right[j]=a[j](第j格的权值)。

我们由k=j-1循环到1,表示从j向左走到k,再回到j,这样的话从k+1到j的格子都走了2次(实际上这其中的格子原来是正数的对分数没贡献,如果原来是负数,则应加上这个负数的2倍)这些和可以在循环k的同时计算出来设为temp,则left[j]=max(left[j],temp+a[k])。

同理我们还可以k=j+1循环到列数n,类似地right[j]=max(right[j],temp+a[k]);

求好这个后我们设dp[i][j]表示停在第i行第j列的最大的分,则有

dp[i][j]=max(dp[i-1][j]+left[j]+right[j]-a[j],

(1<=k<j)max(dp[i-1][k]+left[k]+sum[j-1]-sum[k]+right[j])

(j<k<=n)max(dp[i-1][k]+ right[k]+sum[k-1]-sum[j]+left[j])

)

初始dp[0][1]=0,dp[0][i!=1]=-inf

所有这些值里取最大即可。最后dp[m][n]为所求。(m是行n是列)

firePhoenix1981 2009-08-27
  • 打赏
  • 举报
回复
用图里面的最短路径算法就可以了

33,028

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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