Dijkstra

#Dijkstra算法一例
今天做京东的在线笔试题,遇到了一道题,原题是这样的:

某人在公司年会上获得了年终奖,他的年终奖是这样的:在一个6*6的棋盘格中,每个格中都放有相应金额的奖品,这个人从左上角开始,每次只能向下或者向右移动一格,所到达的格里的奖品即为他所有,终点为右下角的格子。要求设计一个算法,求出他所能得到的最大的奖品金额。

inout example:
200 120 400 150 180 300
150 250 360 120 300 130
350 300 250 100 500 260
100 150 260 320 100 150
500 130 260 100 200 170
160 100 250 200 600 200

output example:
3100

这个题目是类似于求单源最短路径,当然这里是求最大值,虽然具体的细节不一样,但思想是一样的。除了某些边上的点,其他地方的点都是有两条路径可以到达这个点,那么可以计算每个点到起始点的所有权的和,这里称为路径总权,这里的各点的权就相当于格子中奖品的金额。分别将两条入路的路径总权与该点的权相加取其大,作为该点的路径总权。路径总权的计算可以倒推到起始点:左上角点。起始点的路径总权就是它的权。最后右下角的格子的路径总权就是所求结果。

这里除了一个存放输入权的6*6数组,还需要一个存储待处理点的队列,每次在处理一个点时,将与该点相邻的两个点放在这个队列里,然后从队列里取点作为下一个要处理的点(这里所说的处理点其实是处理与它相邻的两个点,这在程序中可以看到)。还要为每个点建立一个状态表,状态表有四个变量,分别是是否被处理过、路径总权dv、入径pv的row、入径pv的col,当然row和col如果不是要打印路径的话是可以不用的。状态表如下

| point | known | dv | pv.x | pv.y |
|--------|--------|-------|--------|
| [0,0] | T | 200 | 0 | 0 |
| [0,1] | F | NULL | NULL |NULL|
| [0,2] | F | NULL | NULL |NULL|
| [0,3] | F | NULL | NULL |NULL|

以此类推,接下来是程序,用c++写的。

#include<iostream>
#include<queue>

using namespace std;

class Node
{
public:
	Node(int row, int col)
	{
		this->row = row;
		this->col = col;
	}
	Node()
	{

	}
	int row;
	int col;
};

class point
{
public:
	int money, known, dv, pv_row, pv_col;
	point()
	{
		known = 0;
	}
};

int main()
{
	point p[6][6];//初始的输入
	
	queue<Node *> points;//存储待处理点的队列

	//读取数据
	for (int i = 0;i < 6;i++)
	{
		for (int j = 0;j < 6;j++)
		{
			cin >> p[i][j].money;
		}
	}

	//将起始点信息写入状态表中
	Node *node = new Node(0,0);
	
	points.push(node);
	p[0][0].known = 1;
	p[0][0].dv = p[0][0].money;
	p[0][0].pv_row = 0;
	p[0][0].pv_col = 0;
	//delete node;

	//如果队列不为空,就一直处理点
	while (!points.empty())
	{
		Node *tempNode = points.front();//从队列中读取点

		//处理与该点相邻的两个点
		int row1, col1,row2,col2;
		int sumTemp=0;
		row1 = (tempNode->row)+1;
		col1 = (tempNode->col);
		row2 = (tempNode->row);
		col2 = (tempNode->col) + 1;

		if (row1 < 6)//保证不越界,越界的话证明处理完了,就没有要处理的点再入队
		{
			Node *newNode1 = new Node(row1, col1);
			points.push(newNode1);
			//delete newNode1;
			sumTemp = p[row1][col1].money + p[tempNode->row][tempNode->col].dv;
			
			if (p[row1][col1].known == 0|| sumTemp > p[row1][col1].dv)
			{
				p[row1][col1].dv = sumTemp;
				p[row1][col1].known = 1;
				p[row1][col1].pv_row = tempNode->row;
				p[row1][col1].pv_col = tempNode->col;
			}
			
		}
		


		if (col2 < 6)
		{
			Node *newNode2 = new Node(row2, col2);
			points.push(newNode2);
			//delete newNode2;
			sumTemp = p[row2][col2].money + p[tempNode->row][tempNode->col].dv;
			if (p[row2][col2].known == 0|| sumTemp > p[row2][col2].dv)
			{
				p[row2][col2].dv = sumTemp;
				p[row2][col2].known = 1;
				p[row2][col2].pv_row = tempNode->row;
				p[row2][col2].pv_col = tempNode->col;
			}
			
		}
		
		points.pop();


	}
	cout << p[5][5].dv << endl;

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值