1. 程式人生 > >UVA 1601 The Morning after Halloween

UVA 1601 The Morning after Halloween

front conn pro lap 數量 有一個 需要 fin space

https://vjudge.net/problem/UVA-1601

題目

你在遊樂場的鬼屋裏當操作員,專門控制鬼屋裏的機器人……某日沒事幹的出題人把這些機器人搬到了其他地方,你需要在最短的時間內遙控機器人讓他們回到原位。所有機器人都可以同時在1秒內朝四個方向(上下左右)移動1格,但是每次移動都必須符合以下條件

  1. 每個格子只能有一個機器人
  2. 任意兩個機器人的位置不能交換
  3. 不能移動到墻裏……

問你需要至少多少時間才能把所有機器人歸位。

輸入包含多組數據

地圖的寬、高和機器人的數量

下面幾行表示地圖,其中小寫字母表示機器人的位置,大寫字母表示機器人的終點,‘#‘表示墻,‘ ‘表示可以走的位置……

輸出每組數據下的最短時間

樣例輸入

5 5 2
#####
#A#B#
#   #
#b#a#
#####
16 4 3
################
## ########## ##
#    ABCcba    #
################
0 0 0
################
### ##    #   ##
##  #  ##   # c#
#  ## ########b#
# ##  # #   #  #
#   # ##  # # ##
## a# #   # #  #
### ## #### ## #
##   #   #  #  #
#  ##### # ## ##
####   #B# #   #
##  C#   #   ###
#  # # ####### #
# ######  A##  #
#        #    ##
################
0 0 0

樣例輸出

7
36
77

題解

只用了一個單向bfs,對空格編號建圖,用前向星……

檢測能否互換需要分n=2和n=3兩種情況考慮

n=2時很簡單

n=3時要考慮$\binom{3}{2}$種情況,頭暈還多想了3個位置都換了的情況,其實這是不可能的,由於只能移動一步,所以加上這個這只是浪費時間……
技術分享圖片

AC代碼(1080ms,去掉浪費時間的部分是750ms)

#include<bits/stdc++.h>
using namespace std;
#define REP(i,x,y) for(register int i=(x); i<(y); i++)
#define REPE(i,x,y) for(register int i=(x); i<=(y); i++)
#ifdef sahdsg
#define DBG(a,...) printf(a, ##__VA_ARGS__)
#else
#define DBG(a,...) (void)0
#endif

#define MAXN 20
#define MAXP 300
int w,h,n;
int cnt;
int mp[MAXN][MAXN];
int st[3],ed[3];
bool vis[MAXP][MAXP][MAXP];
int hed[131072], nxt[131072], poi[131072], fstar=0;
inline void conn(int f, int t) {
	nxt[fstar]=hed[f];
	poi[fstar]=t;
	hed[f]=fstar++;
}
struct node {
	int s;
	int p[3];
	node(int *x, int y=0):s(y) {memcpy(p,x,sizeof p);}
};
inline void bfs() {
	memset(vis,0,sizeof vis);
	queue<node> q;
	q.push(node(st));
	int ans=-1;
	while(!q.empty()) {
		node now = q.front();q.pop();
		if(memcmp(now.p,ed,sizeof ed)==0) {ans=now.s; break;}
		int i[3],k[3],dis[3];
		REP(i,0,n) dis[i]=now.p[i];
		memset(k,0,sizeof k);
		#define CHK k[0]!=k[1] && k[1]!=k[2] && k[2]!=k[0]
		for(i[0]=hed[now.p[0]]; ~i[0]; i[0]=nxt[i[0]]) {
			k[0]=poi[i[0]];
			if(n>=2) for(i[1]=hed[now.p[1]]; ~i[1]; i[1]=nxt[i[1]]) {
				k[1]=poi[i[1]];
				if(n>=3) for(i[2]=hed[now.p[2]]; ~i[2]; i[2]=nxt[i[2]]){
					k[2]=poi[i[2]];
					if(!vis[k[0]][k[1]][k[2]]) if(CHK) {
						if(dis[0]==k[1] && dis[1]==k[0]) continue;
						if(dis[0]==k[2] && dis[2]==k[0]) continue;
						if(dis[1]==k[2] && dis[2]==k[1]) continue;
						
						int j[3],l[3];
						memcpy(j,k,sizeof j);memcpy(l,dis,sizeof j);
						sort(j,j+3);sort(l,l+3);
						if(memcmp(j,l,sizeof j)==0) continue;
						vis[k[0]][k[1]][k[2]]=1;
						q.push(node(k,now.s+1));
					}
				}
				else if(!vis[k[0]][k[1]][0]) if(k[0]!=k[1]) {
					if(k[0]==dis[1] && k[1]==dis[0]) continue;
					vis[k[0]][k[1]][0]=1; q.push(node(k,now.s+1));
				}
			} else if(!vis[k[0]][0][0]){vis[k[0]][0][0]=1; q.push(node(k,now.s+1));}
		}
	}
	printf("%d\n", ans);
}
int main() {
	#ifdef sahdsg
	freopen("in.txt", "r", stdin);
	#endif
	while(~scanf("%d%d%d", &w, &h, &n) && w) {
		cnt=0;
		memset(hed,-1,sizeof hed);
		memset(st,0,sizeof st);
		memset(ed,0,sizeof ed);
		fstar=0;
		REP(i,0,h) REP(j,0,w) {
			char ch = getchar();
			if(ch<‘ ‘)ch=getchar();
			if(ch==‘#‘) {mp[i][j]=-1; continue;}
			mp[i][j]=cnt;
			if(ch>=‘a‘ && ch<=‘z‘) st[ch-‘a‘]=cnt;
			else if(ch>=‘A‘ && ch<=‘Z‘) ed[ch-‘A‘]=cnt;
			conn(cnt,cnt);
			if(i>0 && mp[i-1][j]>=0) conn(mp[i-1][j],cnt),conn(cnt,mp[i-1][j]);
			if(j>0 && mp[i][j-1]>=0) conn(mp[i][j-1],cnt),conn(cnt,mp[i][j-1]);
			cnt++;
		}
		bfs();
	}
	
	return 0;
}

比較慢,可以用雙向bfs或A*優化……

UVA 1601 The Morning after Halloween