拯救公主
【题目描述】
有这样一张地图,地图上标记了勇者和公主分别所处的位置、一些无法踏入的禁区、一些传送门以及一些宝石,通过一个传送门能够瞬间转移到任意一个传送门,并且需要集齐K种宝石才能救出公主。
地图为一个R*C的字符矩阵,字符“S”表示勇者所处的位置,字符“E”表示公主所处的位置,字符“#”表示无法踏入的禁区,字符“$”表示传送门,字符“.”表示安全的位置,数字0~4表示宝石的种类。
勇者每次可以从当前位置到达其上下左右四个方向上的任意一个位置,但不能越过地图边界,勇者每走一步需要花费一个单位时间,从一个传送门瞬间转移到另一个传送门不需要花费额外时间,当勇者到达宝石所处的位置时,便视为得到了该宝石,不需要花费额外时间。
【输入描述】
第一行输入一个正整数T(1 <= T <= 10),表示共有T组数据;
每组数据输入格式如下:
第一行输入三个正整数R、C(2 <= R,C <= 200)、K,表示地图为一个R*C的矩阵,以及需要集齐K种宝石;
接下来R行,每行输入了C个字符,其含义如题中所述。
数据保证仅有一个“S”和“E”,“$”的数量不超过10个,宝石的类型在0~4的范围内。
【输出描述】
对于每组数据输出一行,每行包含一个数,表示勇者救出公主所花费的最少时间,如果勇者无法救出公主,输出“oop!”。
【样例输入】
1
7 8 2
........
..S..#0.
.##..1..
.0#.....
...1#...
...##E..
...1....
【样例输出】
11
源代码: #include<cstdio> #include<cstring> #include<queue> #define INF 0x44444444 using namespace std; queue <int> Q; int XDoor[10],YDoor[10],DP[201][201][1<<5]; int x[4]={1,0,-1,0}; int y[4]={0,1,0,-1}; char Map[201][201]; int main() { int T; scanf("%d",&T); while (T--) { int m,n,k,T1,T2,Num(0); memset(DP,0x44,sizeof(DP)); scanf("%d%d%d",&n,&m,&k); for (int a=0;a<n;a++) { scanf("%s",Map[a]); for (int b=0;b<m;b++) { switch (Map[a][b]) { case '$': XDoor[Num]=a; YDoor[Num++]=b; break; case 'S': Q.push(a); Q.push(b); Q.push(0); DP[a][b][0]=0; break; case 'E': T1=a; T2=b; break; default : break; } } } while (!Q.empty()) { int t1=Q.front(); Q.pop(); int t2=Q.front(); Q.pop(); int t=Q.front(); Q.pop(); for (int a=0;a<4;a++) { int X=t1+x[a]; int Y=t2+y[a]; if (X<0||Y<0||X==n||Y==m||Map[X][Y]=='#') continue; int T=DP[t1][t2][t]+1; int S=t; if ('0'<=Map[X][Y]&&Map[X][Y]<='4') S|=1<<Map[X][Y]-'0'; if (T>=DP[X][Y][S]) continue; if (Map[X][Y]=='$') for (int b=0;b<Num;b++) { DP[XDoor[b]][YDoor[b]][S]=T; Q.push(XDoor[b]); Q.push(YDoor[b]); Q.push(S); } else { DP[X][Y][S]=T; if (Map[X][Y]=='E'&&S==(1<<k)-1) continue; Q.push(X); Q.push(Y); Q.push(S); } } } if (DP[T1][T2][(1<<k)-1]==INF) printf("oop!\n"); else printf("%d\n",DP[T1][T2][(1<<k)-1]); } return 0; }