一、PROBLEM 1:A - Maze
1.题目
东东(是咕咕东?咕咕东是谁?)有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸(助教出的题目格外亲民),这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。
input:输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
output:输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。
Sample Input
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
Sample Output
(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开始,且以左上角为原点。另外注意,输出中分隔坐标的逗号后面应当有一个空格。
2.解题思路
position结构体表明地图上的点,maze为地图(在地图外另加一圈1标识墙),offset为前进的坐标偏移量。
设置栈来存储路径,将原点push,当该点有可移动的地方,就将下一点push进栈,当下一点没有可移动的地方,就返回该点,直到找到妹子所在地。
输出在这里再设置一个栈,存储正向路径并输出。
3.c++代码
#include<iostream>
#include<stack>
using namespace std;
struct position
{
int row;
int col;
};
int main()
{
stack<position> path;//存储路径
//设置上下左右的偏移量
position offset[4];
offset[0].row=0;offset[0].col=1;//right
offset[1].row=1;offset[1].col=0;//down
offset[2].row=0;offset[2].col=-1;//left
offset[3].row=-1;offset[3].col=0;//up
//声明地图(5+2)
int **maze=new int*[7];
for(int i=0;i<7;i++)
maze[i]=new int[7];
//设置墙(2)
for(int i=0;i<7;i++)
for(int j=0;j<7;j++)
if(i==0||i==6||j==0||j==6)
maze[i][j]=1;
//输入地图
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
cin>>maze[i][j];
//寻找路径
position here;
here.row=1;here.col=1;
maze[1][1]=1;//已走过,不可回头
path.push(here);
int option=0;//初始化选择为右
while(here.row!=5||here.col!=5)//不到终点
{
option=0;
while(option<=3)
{
if(maze[here.row+offset[option].row][here.col+offset[option].col]==0)
{
here.row+=offset[option].row;
here.col+=offset[option].col;
maze[here.row][here.col]=1;
path.push(here);
//cout<<'p'<<path.top().row<<' '<<path.top().col<<endl;
break;
}
option++;
}
if(option>3)//该地没有可移动的地方
{
maze[here.row][here.col]=1;
path.pop();
here=path.top();
}
}
//输出路径
stack<position> path2;
while(!path.empty())
{
path2.push(path.top());
//cout<<'a'<<path2.top().row<<' '<<path2.top().col<<endl;
path.pop();
}
while(!path2.empty())
{
cout<<'('<<path2.top().row-1<<','<<' '<<path2.top().col-1<<')'<<endl;
path2.pop();
}
return 0;
}
二、PROBLEM2:B - Pour Water
1.题目
倒水问题 “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
2.解题思路
(1)倒水过程中有六种状态:fill a,fill b,empty a,empty b,pour a b,pour b a,各自的限制条件在代码中有体现。队列存储求解中的各种水杯状态,初始化状态为a=0,b=0,每种状态都要将六种倒水的方法遍历一遍,如果出现新的水杯状态,就push队列,直到找到c。
(2)遍历输出时,用map将水杯目前的状态与转化前上次的状态绑定,用于输出路径。opera用于输出转化的操作。
(3)注意子函数中栈和vis都要在下一次循环前置位初始值。
3.c++代码
#include<iostream>
#include<math.h>
#include<string>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
struct water
{
int a;
int b;
string op;//标识每种状态由哪种操作得来的
bool operator<(const water& _w)const//重载,不然会错误
{
if(a!=_w.a)return a<_w.a;
else return b<_w.b;
}
};
const int MAX=1000;
int vis[MAX][MAX];//表示该状态是否已有,自动初始化为0
void bfs(int a,int b,int c)
{
water w1;
map<water,water> myMap;//将现在的状态与相应的上次状态绑定
queue<water> thisQ;
w1.a=0;w1.b=0;w1.op="NULL";
vis[w1.a][w1.b]=1;
thisQ.push(w1);
while(!thisQ.empty())
{
water w2;
w2=thisQ.front();thisQ.pop();
if(w2.a==c||w2.b==c)//找到符合要求的水量
{
water w4;
string opera[1000];
int t=0;
while(w2.a!=0||w2.b!=0)//
{
opera[t]=w2.op;
w4=myMap[w2];
w2=w4;
t++;
}
for(int i=t-1;i>=0;i--)
cout<<opera[i]<<endl;
cout<<"success"<<endl;
break;
}
//六种状态
if(w2.a<a)//fill a,a不满
{
water w3;
w3.a=a;w3.b=w2.b;w3.op="fill A";
if(vis[w3.a][w3.b]==0)//该状态未有过
{
thisQ.push(w3);
vis[w3.a][w3.b]=1;
myMap[w3]=w2;//w3的上个状态是w2
}
}
if(w2.b<b)//fill b,b不满
{
water w3;
w3.a=w2.a;w3.b=b;w3.op="fill B";
if(vis[w3.a][w3.b]==0)//该状态未有过
{
//cout<<"2222"<<endl;
thisQ.push(w3);
vis[w3.a][w3.b]=1;
myMap[w3]=w2;//w3的上个状态是w2
}
}
if(w2.a>0)//empty a,a有水
{
water w3;
w3.a=0;w3.b=w2.b;w3.op="empty A";
if(vis[w3.a][w3.b]==0)//该状态未有过
{
thisQ.push(w3);
vis[w3.a][w3.b]=1;
myMap[w3]=w2;//w3的上个状态是w2
}
}
if(w2.b>0)//empty b,b有水
{
water w3;
w3.a=w2.a;w3.b=0;w3.op="empty B";
if(vis[w3.a][w3.b]==0)//该状态未有过
{
thisQ.push(w3);
vis[w3.a][w3.b]=1;
myMap[w3]=w2;//w3的上个状态是w2
}
}
if(w2.a>0&&(w2.b<b))//pour a b,a有水b不满
{
water w3;
if(w2.a>(b-w2.b))//把b倒满后a仍有水
{
w3.a=w2.a-(b-w2.b);
w3.b=b;
w3.op="pour A B";
}
else //a可以完全倒进b中
{
w3.a=0;
w3.b=w2.b+w2.a;
w3.op="pour A B";
}
if(vis[w3.a][w3.b]==0)//该状态未有过
{
thisQ.push(w3);
vis[w3.a][w3.b]=1;
myMap[w3]=w2;//w3的上个状态是w2
}
}
if(w2.b>0&&(w2.a<a))//pour b a,b有水a不满
{
water w3;
if(w2.b>(a-w2.a))//把a倒满后b仍有水
{
w3.b=w2.b-(a-w2.a);
w3.a=a;
w3.op="pour B A";
}
else //b可以完全倒进a中
{
w3.b=0;
w3.a=w2.a+w2.b;
w3.op="pour B A";
}
if(vis[w3.a][w3.b]==0)//该状态未有过
{
thisQ.push(w3);
vis[w3.a][w3.b]=1;
myMap[w3]=w2;//w3的上个状态是w2
}
}
}
while(!thisQ.empty())
thisQ.pop();
for(int i=0;i<MAX;i++)
for(int j=0;j<MAX;j++)
vis[i][j]=0;
}
int main()
{
int a,b,c;
while(cin>>a>>b>>c)
{
bfs(a,b,c);
}
return 0;
}