【HDU】5025 Saving Tang Monk 状压最短路

传送门:【HDU】5025 Saving Tang Monk


题目分析:这题一开始想都没想就敲了优先队列+dij。。然后TLE了。。。

后来发现是一个稀疏图。。换成spfa就过了。。

这是一个四维最短路,x轴,y轴,拿到第几个钥匙,打怪的状态(状压),然后就是很简单的状压最短路了。

要注意到钥匙不用状压,因为拿到钥匙是有顺序的。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )
#define clr( a , x ) memset ( a , x , sizeof a )
#define CPY( a , x ) memcpy ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define mid ( ( l + r ) >> 1 )
#define root 1 , 1 , n
#define rt o , l , r

const int MAXN = 105 ;
const int MAXQ = 3000005 ;
const int INF = 0x3f3f3f3f ;

struct Node {
	int x , y , u , s ;
	Node () {}
	Node ( int x , int y , int u , int s ) : x ( x ) , y ( y ) , u ( u ) , s ( s ) {}
} Q[MAXQ] ;

int head , tail ;
char G[MAXN][MAXN] ;
int d[MAXN][MAXN][10][33] ;
int map[MAXN][MAXN] ;
bool vis[MAXN][MAXN][10][33] ;
int path[4][2] = { { 1 , 0 } , { -1 , 0 } , { 0 , 1 } , { 0 , -1 } } ;
int sx , sy ;
int ex , ey ;
int n , m ;

int dijkstra () {
	int ans = INF ;
	clr ( d , INF ) ;
	head = tail = 0 ;
	d[sx][sy][0][0] = 0 ;
	Q[tail ++] = Node ( sx , sy , 0 , 0 ) ;
	while ( head != tail ) {
		Node now = Q[head ++] ;
		if ( head == MAXQ ) head = 0 ;
		if ( now.u == m && now.x == ex && now.y == ey ) {
			ans = min ( ans , d[now.x][now.y][now.u][now.s] ) ;
			continue ;
		}
		vis[now.x][now.y][now.u][now.s] = 0 ;
		rep ( i , 0 , 4 ) {
			int nx = now.x + path[i][0] ;
			int ny = now.y + path[i][1] ;
			if ( nx < 0 || nx >= n || ny < 0 || ny >= n || G[nx][ny] == '#' ) continue ;
			int nu = now.u ;
			int ns = now.s ;
			int nd = 1 ;
			if ( G[nx][ny] == 'S' ) {
				if ( ! ( ns & ( 1 << map[nx][ny] ) ) {
					ns |= ( 1 << map[nx][ny] ) ;
					++ nd ;
				}
			}
			if ( G[nx][ny] <= '9' && G[nx][ny] > '0' ) {
				int tmp = G[nx][ny] - '0' ;
				if ( tmp == nu + 1 ) ++ nu ;
			}
			if ( d[nx][ny][nu][ns] > d[now.x][now.y][now.u][now.s] + nd ) {
				d[nx][ny][nu][ns] = d[now.x][now.y][now.u][now.s] + nd ;
				if ( !vis[nx][ny][nu][ns] ) {
					Q[tail ++] = Node ( nx , ny , nu , ns ) ;
					if ( tail == MAXQ ) tail = 0 ;
					vis[nx][ny][nu][ns] = 1 ;
				}
			}
		}
	}
	return ans == INF ? -1 : ans ;
}

void solve () {
	int cnt = 0 ;
	clr ( vis , 0 ) ;
	rep ( i , 0 , n ) {
		scanf ( "%s" , G[i] ) ;
		rep ( j , 0 , n ) {
			if ( G[i][j] == 'K' ) {
				sx = i ;
				sy = j ;
			} else if ( G[i][j] == 'T' ) {
				ex = i ;
				ey = j ;
			} else if ( G[i][j] == 'S' ) {
				map[i][j] = cnt ++ ;
			}
		}
	}
	int step = dijkstra () ;
	if ( ~step ) printf ( "%d\n" , step ) ;
	else printf ( "impossible\n" ) ;
}

int main () {
	while ( ~scanf ( "%d%d" , &n , &m ) && ( n || m ) ) solve () ;
	return 0 ;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值