题目地址
这里提供一种图论解法 。
设计状态为四元组 ( P x , P y , B x , B y ) (Px,Py,Bx,By) (Px,Py,Bx,By) 分别代表人的坐标和箱子的坐标 。
设计路程为二元组 D i s ( P u s h , W a l k ) Dis(Push,Walk) Dis(Push,Walk) 分别代表推箱子的次数和走路的次数。
路程 A A A大于路程 B B B ,当 A . P u s h > B . P u s h 或 ( A . P u s h = = B . P u s h 且 A . W a l k > B . W a l k ) A.Push >B.Push或(A.Push==B.Push且A.Walk>B.Walk) A.Push>B.Push或(A.Push==B.Push且A.Walk>B.Walk)
bool Cmp (const Dis &A , const Dis &B) {
if (A.Push != B.Push ) return A.Push > B.Push ;
else return A.Walk > B.Walk;
}
两个路程叠加,需要把两个属性分别叠加:
Dis Plus (Dis &A , Dis &B) {
Dis C ;
C.Push = A.Push + B.Push ;
C.Walk = A.Walk + B.Walk ;
return C ;
}
然后用死了的 S P F A SPFA SPFA 就可以解决图论问题了
#include
#include
#define re register
#define Clean(X,K) memset(X,K,sizeof(X))
#define Jud(X,Y) (X<1||X>N||Y<1||Y>M||A[X][Y])
#define GC getchar()
int Qread () {
int X = 0 ;
char C = GC ;
while (C > '9' || C < '0') C = GC ;
while (C >='0' && C <='9') {
X = X * 10 + C - '0' ;
C = GC ;
}
return X ;
}
const int Maxn = 25 , Maxq = Maxn * Maxn , INF = 20021020 * 5 , Dx[]= {-1,1,0,0} , Dy[]= {0,0,-1,1};
const char C[]= {'N','S','W','E'} , c[]= {'n','s','w','e'} ;
char Ans[Maxn * Maxn] = "";
int Vis[Maxn][Maxn][Maxn][Maxn] ,N , M ,A[Maxn][Maxn] , Ex , Ey , Px[Maxn * Maxn * Maxn * Maxn] , Py[Maxn * Maxn * Maxn * Maxn] , Bx[Maxn * Maxn * Maxn * Maxn] , By[Maxn * Maxn * Maxn * Maxn];
char Nxt[Maxn][Maxn][Maxn][Maxn];
struct Node {
int X1 ,Y1 , X2 , Y2 ;
};
Node FT[Maxn][Maxn][Maxn][Maxn] , E;
Node Findf(Node X) {
if (FT[X.X1][X.Y1][X.X2][X.Y2].X2!=0)FT[X.X1][X.Y1][X.X2][X.Y2] = Findf(FT[X.X1][X.Y1][X.X2][X.Y2]) ;
int Ln = strlen (Ans) ;
Ans[Ln] = Nxt[X.X1][X.Y1][X.X2][X.Y2];
Ans[Ln + 1] = '\0' ;
return FT[X.X1][X.Y1][X.X2][X.Y2] ;
}
struct Dis {
int Push , Walk ;
};
Dis Plus (Dis &A , Dis &B) {
Dis C ;
C.Push = A.Push + B.Push ;
C.Walk = A.Walk + B.Walk ;
return C ;
}
bool Cmp (const Dis &A , const Dis &B) {
if (A.Push != B.Push ) return A.Push > B.Push ;
else return A.Walk > B.Walk;
}
/*
头文件和准备工作
1. SPFA用到的队列分别是 Px[Maxn * Maxn * Maxn * Maxn] , Py[Maxn * Maxn * Maxn * Maxn] , Bx[Maxn * Maxn * Maxn * Maxn] , By[Maxn * Maxn * Maxn * Maxn];
各自代表了人的坐标,箱子的坐标。
2.定义距离为二元组(推动的次数,走的步数)
3.定义比较和叠加函数Plus和Cmp ;
4.Nxt数组记录了每一步所走的方向,用于递归输出路径。
*/
Dis Mdis[Maxn][Maxn][Maxn][Maxn] ;
Dis One , Zero , _INF ;
Dis SPFA() {
int H = 0 , T = 1 ;
Dis Ans = _INF ;
Clean( Vis , 0) , Clean(Mdis , 0x3f ) ;
Clean(FT, 0) ;
Mdis[Px[1]][Py[1]][Bx[1]][By[1]] = Zero ;
Vis[Px[1]][Py[1]][Bx[1]][By[1]] = 1 ;
while (H < T) {
++ H ;
Vis[Px[H]][Py[H]][Bx[H]][By[H]] = 0 ;
Node XX;
XX.X1 = Px[H] , XX.Y1 = Py[H] , XX.X2 = Bx[H] , XX.Y2 = By[H] ;
if (Bx[H] == Ex && By[H] == Ey) {
if (Cmp (Ans , Mdis[Px[H]][Py[H]][Bx[H]][By[H]] ) ) {
Ans = Mdis[Px[H]][Py[H]][Bx[H]][By[H]] ;
E.X1 = Px[H] , E.Y1 = Py[H] , E.X2 = Bx[H] , E.Y2 = By[H] ;
}
}
for (re int i = 0 ; i < 4 ; ++ i) {
int Kx = Dx[i] + Px[H] , Ky = Dy[i] + Py[H];
if (Jud (Kx , Ky)) continue ;
if (Kx == Bx[H] && Ky == By[H]) {
int Tx = Dx[i] + Bx[H] , Ty = Dy[i] + By[H] ;
if (Jud (Tx , Ty)) continue ;
if (Cmp (Mdis[Kx][Ky][Tx][Ty] , Plus (Mdis[Px[H]][Py[H]][Bx[H]][By[H]] , One))) {
Mdis[Kx][Ky][Tx][Ty] = Plus (Mdis[Px[H]][Py[H]][Bx[H]][By[H]] , One) ;
FT[Kx][Ky][Tx][Ty] = XX ;
Nxt[Kx][Ky][Tx][Ty] = C[i] ;
if (Vis[Kx][Ky][Tx][Ty]) continue ;
++ T ;
Vis[Kx][Ky][Tx][Ty] = 1 ;
Px[T] = Kx , Py[T] = Ky , Bx[T] = Tx , By[T] = Ty;
}
continue ;
}
if (Cmp (Mdis[Kx][Ky][Bx[H]][By[H]] ,Mdis[Px[H]][Py[H]][Bx[H]][By[H]] )) {
Mdis[Kx][Ky][Bx[H]][By[H]] = Mdis[Px[H]][Py[H]][Bx[H]][By[H]] ;
FT[Kx][Ky][Bx[H]][By[H]] = XX ;
Nxt[Kx][Ky][Bx[H]][By[H]] = c[i] ;
if (Vis[Kx][Ky][Bx[H]][By[H]]) continue ;
++ T ;
Vis[Kx][Ky][Bx[H]][By[H]] = 1 ;
Px[T] = Kx , Py[T] = Ky , Bx[T] = Bx[H] , By[T] = By[H] ;
}
}
}
return Ans;
}
/*
SPFA求最短路
实际上还是SPFA的模板,修改了路线长短的判断。
*/
int main () {
One.Push = 1 ;
One.Walk = 0 ;
Zero.Push = Zero.Walk = 0;
_INF.Push = _INF.Walk = INF;
/*
这里定义了One和Zero,分别是0步和推1步,可以直接用在SPFA里面。
*/
//freopen ("UVA589.in" , "r" , stdin) ;
N = Qread () , M = Qread() ;
int T = 0 ;
while (N + M) {
++T ;
Clean(Ans, 0) ;
Ans[0] = '\0' ;
Clean(A , 0) ;
Clean(Nxt , 0) ;
for (re int i = 1 ; i <= N; ++ i)
for (re int j = 1 ; j <= M; ++ j) {
char C = GC ;
while (C != '.' && C != '#' && C !='S' && C != 'T' && C != 'B') C = GC ;
A[i][j] = (C == '#' ? 1 : 0) ;
if (C == 'S') Px[1] = i , Py[1] = j ;
if (C == 'B') Bx[1] = i , By[1] = j ;
if (C == 'T') Ex= i , Ey = j ;
}
//读入数据
Dis MinL = SPFA() ;//SPFA 计算最短路
Findf(E) ;//递归查找路径
printf ("Maze #%d\n" , T) ;
if (MinL.Push == INF) printf ("Impossible.\n");
else
printf ("%s\n" , Ans) ;
putchar(10) ;
N = Qread() , M = Qread() ;
}
fclose (stdin) ;
fclose (stdout);
return 0;
}