week2作业

A题目:
东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。

输入:输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
输出:输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。

样例输入:
0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0
样例输出:
(0, 0)
(1, 0)
(2, 0)
(3, 0)
(3, 1)
(3, 2)
(2, 2)
(1, 2)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)
Hint :坐标(x, y)表示第x行第y列,行、列的编号从0开始,且以左上角为原点。
另外注意,输出中分隔坐标的逗号后面应当有一个空格。
整体思路:
迷宫类题目具有一定的固定解法,利用队列先进先出的特性,我们可以利用bfs的思想对距离进行广搜,而逐步获取距离连续的点,这样相当于在寻找路径的时候为每个点做了标记,使得我们再一步获取路径时更方便。本道题目有着特殊的限制:即保证了线路只有一条,这使得我们回来找路径时处理更简单,考虑的更少。例如在代码段func2中,我们利用递归寻找路径,因为输出是从(0,0)点开始的,如果我们从原点考虑以末尾点为结束标志的话,我们func2中的break语句必须要加,因为从头开始循环找路径时路径会分叉,但是由于题目保证路径只有一条,所以我们可以考虑从末尾点开始考虑,以初始点作为递归弹出点,这样可以保证路径不会分叉。当然,我们同样也可以考虑利用break语句避免分叉输出,而且又能够节省时间消耗。

#include<iostream>
#include<queue>
using namespace std;
int fun[5][5];
int x[4]={1,-1,0,0};
int y[4]={0,0,1,-1};
void func(int fun[][5])
{
	queue<pair<int,int> > mp;
	pair<int,int> p(0,0);
	mp.push(p);//(0,0)点入队列;
	while(!mp.empty())
	{
		pair<int,int>a=mp.front();
		mp.pop();
		for(int i=0;i<4;i++)//对上下左右四个点分别进行考虑;
		{
			int newx=a.first+x[i];
			int newy=a.second+y[i];
			if(0<=newx&&newx<=4&&0<=newy&&newy<=4)//防止越过边界;
			{
				if(fun[newx][newy]==0)
				{
					fun[newx][newy]=fun[a.first][a.second]+1;
					mp.push(pair<int,int>(newx,newy));
					if(fun[4][4]!=0)//循环终止条件;
					return;
				}
			}
		}		
	}
}
void func2(int fun[][5],int a,int b)
{
	if(a==0&&b==0)
	{
		cout<<"("<<0<<","<<" "<<0<<")"<<endl;
		return;
	}
	for(int i=0;i<4;i++)
	{
		if(0<=a-x[i]&&a-x[i]<=4&&0<=b-y[i]&&b-y[i]<=4)
		{
			if(fun[a-x[i]][b-y[i]]==fun[a][b]-1)
			{
				func2(fun,a-x[i],b-y[i]);//利用递归,从终点回溯的起点;
				cout<<"("<<a<<","<<" "<<b<<")"<<endl;
				//break;//此题不写也可以,但写了可以降低时间消耗;
			}
		}
	}
}
int main()
{
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++)
		{
			cin>>fun[i][j];
		}
	}
	fun[0][0]=2;//为了不与输入的0,1搞混,我们取值为2;
	func(fun);
	func2(fun,4,4); 
}

B题目:
倒水问题
“fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。
Input:
输入包含多组数据。每组数据输入 A, B, C
数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。
Output:
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。
Sample Input:
2 7 5
2 7 4
Sample Output
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success
Notes:如果你的输出与Sample Output不同,那没关系。对于某个"A B C"本题的答案是多解的,不能通过标准的文本对比来判定你程序的正确与否。
所以本题由 SPJ(Special Judge)程序来判定你写的代码是否正确。

整体思路:对于倒水问题,其实是一个隐式图问题,其解决方案与A题的思路有着一定的相似之处,A杯与B杯的状态属于一个点,于是我们借助A题的思想,其每一个点的扩展方向有大方向分四种,小方向分六中,将A倒空,将B倒空,将A倒入B中,将B倒入A中。因为我们最终是要到达A杯中或B杯中水为定容量,故一种状态到达一次即可,此时,我们可以利用map的映射特性,将到达过的状态加入map,这里对于Map的第一维和第二维的问题存在一个选择问题,在这里,我们将end作为第一维,将from作为第二维,这其中from与end状态的关系相似一棵树,应当将出度的点作为第一维。同样利用队列的特性以及bfs的思想进行搜索。不过,由于这种映射关系,我们只能够从末位状态进行考虑追溯的原始状态,这样,我们将每一步的操作存入到一个vector中,最终我们再倒序输出vector中的元素即可。

#include<iostream>
#include<map>
#include<string>
#include<queue>
#include<vector>
using namespace std;
struct status {
	int x, y;
	status(){
	}
	status(int a, int b) {
		x = a;
		y = b;
	}
	bool operator<(const status& p)const {
		return x == p.x ? y < p.y : x < p.x;
	}
};
map<status, status> mp;//第一维表示end,第二维表示from;
void func(int a, int b, int c) {
	queue<status> ls;
	status from(0, 0);	ls.push(from);
	while (!ls.empty()) {
		from = ls.front();
		ls.pop();
		//将a杯倒空;
		if (mp.find(status(0, from.y)) == mp.end()) {
			ls.push(status(0, from.y));
			mp[status(0, from.y)] = status(from.x, from.y);
		}
		//将b杯倒空:
		if (mp.find(status(from.x, 0)) == mp.end()) {
			ls.push(status(from.x, 0));
			mp[status(from.x, 0)] = status(from.x, from.y);
		}
		//将a杯倒满; 
	    if (mp.find(status(a, from.y)) == mp.end()) {
			ls.push(status(a, from.y));
			mp[status(a, from.y)] = status(from.x, from.y);
		}
	    //将b杯倒满;
		if (mp.find(status(from.x, b)) == mp.end()) {
			ls.push(status(from.x, b));
			mp[status(from.x, b)] = status(from.x, from.y);	
		}
		//将a中的水倒入b杯中;
		if (from.x+from.y > b) {
			if (mp.find(status(from.x + from.y - b, b)) == mp.end()) {
				ls.push(status(from.x + from.y - b, b));
				mp[status(from.x + from.y - b, b)] = status(from.x, from.y);
			}

		} else {
			if (mp.find(status(0, from.x + from.y)) == mp.end()) {
				ls.push(status(0, from.x + from.y));
				mp[status(0, from.x + from.y)] = status(from.x, from.y);
			}
		}
		//将b中的水倒入a中; 
		if (from.x+from.y > a) {
			if (mp.find(status(a, from.x + from.y - a)) == mp.end()) {
				ls.push(status(a, from.x + from.y - a));
				mp[status(a, from.x + from.y - a)] = status(from.x, from.y);
			}
		} else {
			if (mp.find(status(from.x + from.y, 0)) == mp.end()) {
				ls.push(status(from.x + from.y, 0));
				mp[status(from.x + from.y, 0)] = status(from.x, from.y);
			}
		}
		if (mp.find(status(0, c)) != mp.end() || mp.find(status(c, 0)) != mp.end())
			break;
	}
}
void print(int a1, int b1, int c1) {
	vector<string> pri;
	string str;
	if (mp.find(status(0, c1)) != mp.end()) {
		int endx = 0, endy = c1;
		int a = -1, b = -1;
		while (!(a == 0 && b == 0)) {
			status from = mp[status(endx, endy)];
			a = from.x;
			b = from.y;
			if (endx == a && endy == 0) {
				str = "empty B";
				pri.push_back(str);
				endx=a;
				endy=b; 
			} else if (endx == a && endy == b1) {
				str = "fill B";
				pri.push_back(str);
				endx=a;
				endy=b; 
			} else if (endx + endy == a + b) {
				if (endx == 0 || endy == b1) {
					str = "pour A B";
					pri.push_back(str);
					endx=a;
				    endy=b; 
				}
				if (endy == 0 || endx == a1) {
					str = "pour B A";
					pri.push_back(str);
					endx=a;
				    endy=b; 
				}
			} else if (endx == 0 && endy == b) {
				str = "empty A";
				pri.push_back(str);
				endx=a;
				endy=b; 
			} else if (endx == a1 && endy == b) {
				str = "fill A";
				pri.push_back(str);
				endx=a;
				endy=b; 
			}
		}
		int size = pri.size();
		for (int i = size - 1; i >= 0; i--) {
			cout << pri[i] << endl;
		}
		cout << "success"<<endl;
		return;
	} else if (mp.find(status(c1, 0)) != mp.end()) {
		int endx = c1, endy = 0;
		int a = -1, b = -1;
		while (!(a == 0 && b == 0)) {
			status from = mp[status(endx, endy)];
			a = from.x;
			b = from.y;
			if (endx == a && endy == 0) {
				str = "empty B";
				pri.push_back(str);
				endx=a;
				endy=b; 
			} else if (endx == a && endy == b1) {
				str = "fill B";
				pri.push_back(str);
				endx=a;
				endy=b; 
			} else if (endx + endy == a + b) {
				if (endx == 0 || endy == b1) {
					str = "pour A B";
					pri.push_back(str);
					endx=a;
				    endy=b; 
				}
				if (endy == 0 || endx == a1) {
					str = "pour B A";
					pri.push_back(str);
					endx=a;
				    endy=b; 
				}
			} else if (endx == 0 && endy == b) {
				str = "empty A";
				pri.push_back(str);
				endx=a;
				endy=b; 
			} else if (endx == a1 && endy == b) {
				str = "fill A";
				pri.push_back(str);
				endx=a;
				endy=b; 
			}
		}
	}
	int size = pri.size();
	for (int i = size - 1; i >= 0; i--) {
		cout << pri[i] << endl;
	}
	cout << "success"<<endl;
}
int main() {
	int a, b, c;
	while(cin >> a >> b >> c)
	{
		mp.clear();
		func(a, b, c);
	    print(a, b, c);
	}
	
}在这里插入代码片
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值