微软201604笔试题目3 Demo Day 动态规划解法

2016年4月6日微软在线笔试题目3 Demo Day

用动态规划方法解之


先上原题



题目意思: 给定一个N*M的矩阵,机器人从起点左上角(0,0)出发,到达终点右下角,其中字符'.'表示可通行区域,字符'b'表示障碍物。

限制条件:机器人初始向右移动,且只能向下或者向右移动,且不可“主动拐弯”,即走到不能走才能拐弯。

题目要求:可任意将矩阵中的'b'修改为‘.’,或者将'.'修改为'b',要求尽可能少的变换,使得机器人到达终点。


解题步骤如下:

1. 定义数据结构。结构体中包含right和down。right表示到达此点后若要向右移动所需变换次数,down表示到达此点后若向下移动所需变换次数。

2.初始化起点。起点的right为0,因机器人初始向右移动,所以从初始点若向下移动的话,初始点右边需为障碍物。

3.初始化第一行。当前点的right值受左侧点的right值和自身是否为障碍物影响。当前点的down值受当前点的right值和右侧点是否为边界或者障碍物影响。

4.初始化第一列。当前点的down值受上方点的down值和自身是否为障碍物影响。当前点的right值受当前点的down值和下方点为否为边界或者障碍物影响。

5.递推处理。对矩阵除第一行和第一列的值进行行扫描。

5.1 首先考虑上方的点。上方点到达当前点后可向右或者向下移动。所以当前点的down值受上方点的down值和自身是否为障碍物影响。当前点的right值受当前的down值和下方是否为边界或者障碍物影响。

5.2然后考虑左侧的点。左侧的点到达后也有两种选择。所以当前点的right值受左侧点right值和自身是否为障碍物影响,当前点的down值受当前点的right值和右侧是否为边界或者障碍物影响。

5.3最后结合5.1和5.2,最后的down值取两个down值的最小值,最后的right值取两个right值的最小值。

6.输出右下角的right和down中的最小值即为解。注:每个点的down和right中的最小值为从起点出发到达此点所需最小的变换次数。


C++代码如下:

#include <iostream>
using namespace std;

struct Info
{
	int right,down;
};
/
//
//  table为输入矩阵,存放初始迷宫信息
//  n为行数
//  m为列数
//  返回值为最小变换次数
//
/
int DemoDay(char table[100][100], int n, int m)
{
	//step.1------------定义结构体--------------------//
	Info info[100][100];
	//step.2------------初始化起点--------------------//
	info[0][0].right = 0;
	//若起点右侧点为障碍,则自动拐弯向下移动
	if (table[0][1] == 'b') info[0][0].down = 0;
	else 					info[0][0].down = 1;
	//step.3------------初始化第一行------------------//
	for (int i=1; i<m; i++)
	{
		//right值受左侧点的right值和自身是否为障碍物影响
		if (table[0][i] == 'b') info[0][i].right = info[0][i-1].right + 1;
		else 					info[0][i].right = info[0][i-1].right;
		//down值受当前点的right值和右侧点是否为边界或者障碍物影响
		if (i+1 == m || table[0][i+1] == 'b') 	info[0][i].down = info[0][i].right;
		else 							   		info[0][i].down = info[0][i].right + 1;
	}
	//step.4------------初始化第一列------------------//
	for (int i=1; i<n; i++)
	{
		//down值受上方点的down值和自身是否为障碍物影响
		if (table[i][0] == 'b') info[i][0].down =  info[i-1][0].down + 1;
		else 					info[i][0].down =  info[i-1][0].down;
		//right值受当前点的down值和下方点为否为边界或者障碍物影响
		if (i+1 == n || table[i+1][0] == 'b') 	info[i][0].right = info[i][0].down;
		else 									info[i][0].right = info[i][0].down + 1;
	}
	//step.5------------递推,行扫描------------------//
	for (int i=1; i<n; i++)
	{
		for (int j=1; j<m; j++)
		{
			int right1,right2,down1,down2;
			//step.5.1---------上方点-----------------//
			//down值受上方点的down值和自身是否为障碍物影响
			if (table[i][j] == 'b') down1 = info[i-1][j].down + 1;
			else  					down1 = info[i-1][j].down;
			//right值受当前的down值和下方是否为边界或者障碍物影响
			if (i+1 == n || table[i+1][j] == 'b') 	right1 = down1;
			else  									right1 = down1 + 1;
			//step.5.2---------左侧点-----------------//
			//right值受左侧点right值和自身是否为障碍物影响
			if (table[i][j] == 'b') right2 = info[i][j-1].right + 1;
			else 					right2 = info[i][j-1].right;
			//down值受当前点的right值和右侧是否为边界或者障碍物影响
			if (j+1 == m || table[i][j+1] == 'b') 	down2 = right2;
			else 									down2 = right2 + 1;
			//step.5.3---------结合-------------------//
			info[i][j].down = min(down1, down2);
			info[i][j].right = min(right1,right2);
		}
	}

	//step.6------------输出且返回--------------------//
	for (int i=0; i<n; i++)
	{
		for (int j=0; j<m; j++)
		{
			cout<<min(info[i][j].right,info[i][j].down)<<" ";
		}
		cout<<endl;
	}
	return min(info[n-1][m-1].right,info[n-1][m-1].down);
}

int main()
{
	int n,m;
	cin>>n>>m;
	char table[100][100];
	for (int i=0; i<n; i++)
	{
		for (int j=0; j<m; j++)
		{
			cin>>table[i][j];
		}
	}
	
	cout<<DemoDay(table,n,m)<<endl;
	return 0;
}

测试用例:

4 8

....bb..

........

.....b..

...bb...



代码在微软笔试中测试为满分。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值