Programación tarea de pensamiento semana2
本次作业的两个题都是BFS的典型应用。
Directorio
Problema A: laberinto
1. Resumen del tema
Dongdong tiene un mapa y quiere encontrar el papel hermano a través del mapa. El mapa muestra que 0 significa que puedes caminar, 1 significa que no puedes caminar, la esquina superior izquierda es la entrada y la esquina inferior derecha es el papel hermano. Estas dos posiciones están garantizadas como 0. Ahora que conoce el mapa, no es difícil para Dongdong encontrar papel hermano. Por favor, escriba un programa para escribir la ruta más corta para que Dongdong encuentre papel hermano.
2 entrada
La entrada es una matriz bidimensional de 5 × 5, que consta de solo dos dígitos 0 y 1, que representa un mapa de matriz normal.
3.Salida
Se generan varias líneas, que representan las coordenadas de la ruta más corta desde la esquina superior izquierda a la esquina inferior derecha, en el formato que se muestra en la muestra. Se garantiza que los datos tendrán una solución única.
4. Muestra
entrada de muestra
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
salida de muestra
(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)
5. La idea general
La idea es relativamente simple: use la pila para simular el proceso BFS, guarde el que llegue con éxito al punto final en la pila y luego use la otra pila para generar el resultado en orden inverso.
6. Código
#include<iostream>
#include<stack>
using namespace std;
//记录点的坐标
class point
{
public:
point(int x,int y)
{
_x=x;
_y=y;
}
void output()
{
cout<<'('<<_x-1<<','<<' '<<_y-1<<')'<<endl;
}
public:
int _x;
int _y;
};
int _dx[]={1,0,0,-1};
int _dy[]={0,-1,1,0};
stack<point> track;
int a[7][7];
int main()
{
//初始化
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
if((i*j==0)||i==6||j==6)
a[i][j]=1;
else cin>>a[i][j];
}
}
//输入起点
point start(1,1);
point terminate(5,5);
track.push(start);
//判断终点条件
while(!(track.top()._x==5&&track.top()._y==5))
{
point now=track.top();
a[now._x][now._y]=1;
int i;
//BFS过程
for(i=0;i<4;i++)
{
int new_x=now._x+_dx[i];
int new_y=now._y+_dy[i];
if(a[new_x][new_y]!=1)
{
a[new_x][new_y]=1;
track.push({new_x, new_y});
break;
}
}
if(i==4) track.pop();
}
int size=track.size();
stack<point> newtrack;
for(int k=0;k<size;k++)
{
point n(track.top()._x,track.top()._y);
track.pop();
newtrack.push(n);
}
for(int i=0;i<size;i++)
{
newtrack.top().output();
newtrack.pop();
}
return 0;
}
Problema B: vierta agua
1. Resumen del tema
Problema de verter agua "llenar A" significa llenar la taza A, "vaciar A" significa vaciar la taza A, "verter AB" significa verter el agua de A en la taza B y vaciar la taza B o A.
2. Muestra de entrada y salida
Entrada
La entrada contiene múltiples conjuntos de datos. Cada grupo de entrada de datos A, B, C rango de datos 0 <A <= B, C <= B <= 1000, A y B son relativamente primos.
Entrada de muestra
2 7 5
2 7 4
Salida
La salida de su programa consistirá en una serie de instrucciones. Estas líneas de salida harán que cualquier tanque contenga exactamente C unidades de agua. La salida de la última línea de cada conjunto de datos debe ser "exitosa". La línea de salida comienza en la columna 1, y no debe haber líneas en blanco ni espacios finales.
Salida de muestra
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success
3. La idea general y el código
Esta pregunta también es la aplicación de BFS. Reemplace la expansión de movimiento arriba-abajo, izquierda-derecha en el problema A por completo, vacío y A (B) a B (A). Mediante el uso del mapa puede registrar el estado del estado anterior de un estado. Luego, de acuerdo con la diferencia entre los dos estados para determinar la operación específica en este paso.
#include<iostream>
#include<queue>
#include<map>
using namespace std;
struct Status
{
int a, b;
bool operator<(const Status &s) const
{
return a!=s.a ? a<s.a : b<s.b;
}
};
/* 递归输出方案 */
void print(Status &p,map<Status, Status> from)
{
if ( from.find(p) == from.end())
{
//cout<<"success"<<endl;
return ;
}
if(p.a == 0&&p.b==0)
{
return ;
}
print(from[p],from); // 递归
int _a=from[p].a;
int _b=from[p].b;
if(p.a!=_a)
{
if(p.a>_a)
{
if(p.b<_b)
cout<<"pour B A"<<endl;
else
cout<<"fill A"<<endl;
} else{
if(p.b>_b)
cout<<"pour A B"<<endl;
else
cout<<"empty A"<<endl;
}
} else{
//p.a==_a
if(p.b>_b)
cout<<"fill B"<<endl;
else
cout<<"empty B"<<endl;
}
//printf("-><%d,%d>", p.a, p.b);
}
void refresh(Status &s, Status &t,map<Status, Status> &from,queue<Status> &Q)
{
if ( from.find(t) == from.end() )
{ // 特判合法,加入队列
from[t] = s;
Q.push(t);
}
}
void bfs(int A, int B, int C,map<Status, Status> from,queue<Status> &Q)
{
// 起点, 两杯水都空
Status s,t;
s.a=0; s.b=0;
Q.push(s);
while (!Q.empty())
{
// 取队首
s = Q.front();
Q.pop();
// 特判到达终点
if (s.a == C || s.b == C) {
print(s,from); // 输出方案
return;
}
// 倒空 a 杯的水
if (s.a > 0) {
t.a = 0; // 倒空
t.b = s.b;// b 杯不变
refresh(s, t,from,Q);
}
// 同理,倒空 b 杯的水
if (s.b > 0) {
t.b = 0; // 倒空
t.a = s.a;// a 杯不变
refresh(s, t,from,Q);
}
// a 杯未满,续满 a 杯
if (s.a < A)
{
// 续满 a 杯
t.a = A;
t.b = s.b;
refresh(s, t,from,Q);
// 考虑倒入
if (s.b != 0)
{
if (s.a + s.b <= A)
{
t.a = s.a + s.b;
t.b = 0;
refresh(s, t,from,Q);
} else
{
t.a = A;
t.b = s.a + s.b - A;
refresh(s, t,from,Q);
}
}
}
// 同理,b 杯未满,续满 b 杯
if (s.b < B)
{
t.a = s.a;
t.b = B;
refresh(s, t,from,Q);
if (s.a != 0)
{
if (s.a + s.b <= B)
{
t.a = 0;
t.b = s.a + s.b;
refresh(s, t,from,Q);
} else
{
t.a = s.a + s.b - B;
t.b = B;
refresh(s, t,from,Q);
}
}
}
}
printf("-1\n");
}
int main()
{
int a;
while (cin>>a) {
queue<Status> Q;
map<Status, Status> from;
int b,c;
cin>>b;
cin>>c;
bfs(a, b, c,from,Q);
cout<<"success"<<endl;
}
return 0;
}