BZOJ 2284 贪食蛇(Sdoi2011 虐心搜索)
2017-03-28 16:23
465 查看
2284: [Sdoi2011]贪食蛇
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 70 Solved: 37
Description
相信大家都玩过贪食蛇游戏,现在有一个改版贪食蛇游戏,跟传统的贪食蛇游戏一样,贪食蛇在活动区域内运动,吃食物,但是这个改版的贪食蛇游戏有着一些特别的规则。
活动区域:
贪食蛇的活动区域是一个R行C列的网格A,贪食蛇活动不能超过这个网格的范围。第i行第j列的方格用Ai,j表示。每个方格有一个整数权值,记作w(Aij)。0<=w(Aij)<=8,w(Aij)=0时,Aij禁止进入;w(Aij)>0时,Aij允许进入。
方向:
对于P=(X0,Y0)、Q=(X1,Y1),有以下四种基本方向:
l 正左(L):X0=X1且Y0=Y1-1,则称P位于Q的正左方向。
l 正右(R):X0=X1且Y0=Y1+1,则称P位于Q的正右方向。
l 正上(U):X0=X1-1且Y0=Y1,则称P位于Q的正上方向。
l 正下(D):X0=X1+1且Y0=Y1,则称P位于Q的正下方向。
贪食蛇:
贪食蛇B是占据若干方格的图形,占据的方格数为贪食蛇的长度,记为m,则贪食蛇从头到尾,用B1、B2、……、Bm表示。记p为贪食蛇的形态,若Bi位于第Xi行第Yi列,则p(Bi)=(Xi,Yi)。初始情况下,m=4,且运动过程中始终需要满足以下限制:
l 对于Bi和Bi+1(1<=i),就是贪食蛇的前、后相邻两部分,必须满足Bi位于Bi+1的L、R、U、D四个方向之一。
l 对于Bi和Bj(1<=i),p(Bi)=(Xi,Yi),p(Bj)=(Xj,Yj),需要满足Xi!=Xj或Yi!=Yj。也就是说,贪食蛇身体的任意一部分不能相交。
食物:
贪食蛇的活动区域内存在一些食物。每个食物位于一个允许进入的方格上,食物不会重叠。每个食物只能被吃一次。
贪食蛇的运动:
如果贪食蛇的头部B1的L、R、U、D四个方向之一的Aij能进入,且Aij上不存在食物,则贪食蛇可以向该方向运动,新的头部位于Aij上。记p’为贪食蛇新的形态,则:
l p’(Bk)=p(Bk-1),当2<=k<=m。
l p’(Bk)=(i,j),当k=1
贪食蛇的进食:
如果贪食蛇的头部B1的L、R、U、D四个方向之一的Aij能进入,且Aij上存在食物,则贪食蛇可以向该方向进食,新的头部位于Aij上,蛇的新长度m’=m+1。记p’为贪食蛇新的位置,则:
l p’(Bk)=p(Bk-1),当2<=k<=m’。
l p’(Bk)=(i,j),当k=1
注意:运动或进食后的贪食蛇形态,仅仅需要考虑变换后的形态是否满足限制,不需要考虑变换的过程。也就是说,原来形态合法的贪食蛇的头部可以运动到尾部的位置,因为在变换后头部和尾部仍不会重叠。
运动或进食所需要的时间:
贪食蛇运动或进食,需要消耗时间。设运动或进食前头部所在的方格是P,运动或进食后头部所在的方格是Q,则此次运动或进食的所消耗的时间为|w(P)-w(Q)|+1。
游戏的会在开始前给出贪食蛇的初始位置和所有食物的位置。你的任务是,以最少的时间令贪食蛇吃完所有食物。
Input
第一行,两个正整数R、C。
接下来R行,每行C个没有空格分隔的数字。其中第i行第j个数字为w(Aij)。
接下来4行,每行2个正整数。第i行的两个整数Xi、Yi,表示p(Bi)=(Xi,Yi)。
接下来一个正整数N,表示食物的数量。
接下来N行,每行2个正整数i、j,表示Aij上存在一个食物。
Output
如果贪食蛇不能吃到所有的食物,输出“No solution.”(不包括引号)。
否则,输出:
第一行,一个整数,表示所需花费的时间;
Sample Input
5 5
11011
11011
11011
11011
11411
1 1
2 1
3 1
4 1
4
5 5
4 4
2 5
1 4
【样例输出】
21
Sample Output
HINT
对于20%的数据,N <= 1。
对于40%的数据,N <= 2。
对于60%的数据,N <= 3。
对于100%的数据,N <= 4。
对于30%的数据,R * C <= 36。
对于100%的数据,R <= 12,C <= 12。
直接上代码吧:(当然不是我写的)
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 70 Solved: 37
Description
相信大家都玩过贪食蛇游戏,现在有一个改版贪食蛇游戏,跟传统的贪食蛇游戏一样,贪食蛇在活动区域内运动,吃食物,但是这个改版的贪食蛇游戏有着一些特别的规则。
活动区域:
贪食蛇的活动区域是一个R行C列的网格A,贪食蛇活动不能超过这个网格的范围。第i行第j列的方格用Ai,j表示。每个方格有一个整数权值,记作w(Aij)。0<=w(Aij)<=8,w(Aij)=0时,Aij禁止进入;w(Aij)>0时,Aij允许进入。
方向:
对于P=(X0,Y0)、Q=(X1,Y1),有以下四种基本方向:
l 正左(L):X0=X1且Y0=Y1-1,则称P位于Q的正左方向。
l 正右(R):X0=X1且Y0=Y1+1,则称P位于Q的正右方向。
l 正上(U):X0=X1-1且Y0=Y1,则称P位于Q的正上方向。
l 正下(D):X0=X1+1且Y0=Y1,则称P位于Q的正下方向。
贪食蛇:
贪食蛇B是占据若干方格的图形,占据的方格数为贪食蛇的长度,记为m,则贪食蛇从头到尾,用B1、B2、……、Bm表示。记p为贪食蛇的形态,若Bi位于第Xi行第Yi列,则p(Bi)=(Xi,Yi)。初始情况下,m=4,且运动过程中始终需要满足以下限制:
l 对于Bi和Bi+1(1<=i),就是贪食蛇的前、后相邻两部分,必须满足Bi位于Bi+1的L、R、U、D四个方向之一。
l 对于Bi和Bj(1<=i),p(Bi)=(Xi,Yi),p(Bj)=(Xj,Yj),需要满足Xi!=Xj或Yi!=Yj。也就是说,贪食蛇身体的任意一部分不能相交。
食物:
贪食蛇的活动区域内存在一些食物。每个食物位于一个允许进入的方格上,食物不会重叠。每个食物只能被吃一次。
贪食蛇的运动:
如果贪食蛇的头部B1的L、R、U、D四个方向之一的Aij能进入,且Aij上不存在食物,则贪食蛇可以向该方向运动,新的头部位于Aij上。记p’为贪食蛇新的形态,则:
l p’(Bk)=p(Bk-1),当2<=k<=m。
l p’(Bk)=(i,j),当k=1
贪食蛇的进食:
如果贪食蛇的头部B1的L、R、U、D四个方向之一的Aij能进入,且Aij上存在食物,则贪食蛇可以向该方向进食,新的头部位于Aij上,蛇的新长度m’=m+1。记p’为贪食蛇新的位置,则:
l p’(Bk)=p(Bk-1),当2<=k<=m’。
l p’(Bk)=(i,j),当k=1
注意:运动或进食后的贪食蛇形态,仅仅需要考虑变换后的形态是否满足限制,不需要考虑变换的过程。也就是说,原来形态合法的贪食蛇的头部可以运动到尾部的位置,因为在变换后头部和尾部仍不会重叠。
运动或进食所需要的时间:
贪食蛇运动或进食,需要消耗时间。设运动或进食前头部所在的方格是P,运动或进食后头部所在的方格是Q,则此次运动或进食的所消耗的时间为|w(P)-w(Q)|+1。
游戏的会在开始前给出贪食蛇的初始位置和所有食物的位置。你的任务是,以最少的时间令贪食蛇吃完所有食物。
Input
第一行,两个正整数R、C。
接下来R行,每行C个没有空格分隔的数字。其中第i行第j个数字为w(Aij)。
接下来4行,每行2个正整数。第i行的两个整数Xi、Yi,表示p(Bi)=(Xi,Yi)。
接下来一个正整数N,表示食物的数量。
接下来N行,每行2个正整数i、j,表示Aij上存在一个食物。
Output
如果贪食蛇不能吃到所有的食物,输出“No solution.”(不包括引号)。
否则,输出:
第一行,一个整数,表示所需花费的时间;
Sample Input
5 5
11011
11011
11011
11011
11411
1 1
2 1
3 1
4 1
4
5 5
4 4
2 5
1 4
【样例输出】
21
Sample Output
HINT
对于20%的数据,N <= 1。
对于40%的数据,N <= 2。
对于60%的数据,N <= 3。
对于100%的数据,N <= 4。
对于30%的数据,R * C <= 36。
对于100%的数据,R <= 12,C <= 12。
直接上代码吧:(当然不是我写的)
#include <cstdio> #include <cstdlib> #include <cstring> const int FX[] = {0, 0, -1, 1}; const int FY[] = {-1, 1, 0, 0}; const char FC[] = {'L', 'R', 'U', 'D'}; const long MaxR = 17, MaxC = 17, MaxS = 1 << 11, MaxQ = 255 * 1200 * 16 * 8, MaxV = 1 << 23; int Map[MaxR][MaxC], Snake_Pos[4][2], Food_N, Food_Map[MaxR][MaxC]; int Stat[MaxS][4], Food_Stat[MaxS][4]; int Queue[MaxQ], Prec[MaxQ]; unsigned char Visit[MaxV]; int Answer_Link, Answer_N, Answer_Time; char Answer_C[MaxR * MaxC]; int input() { int r, c; char map_tmp[MaxC << 1]; scanf("%d%d", &r, &c); for (int i = 1; i <= r; ++ i) { scanf("%s", map_tmp); for (int j = 1; j <= c; ++ j) Map[i][j] = map_tmp[j - 1] - '0'; } for (int i = 0; i <= r + 1; ++ i) Map[i][0] = Map[i][c + 1] = 0; for (int i = 1; i <= c; ++ i) Map[0][i] = Map[r + 1][i] = 0; for (int i = 0; i < 4; ++ i) scanf("%d%d", &Snake_Pos[i][0], &Snake_Pos[i][1]); memset(Food_Map, 0, sizeof(Food_Map)); scanf("%d", &Food_N); for (int i = 1; i <= Food_N; ++ i) { scanf("%d%d", &r, &c); Food_Map[r][c] = i; } return 0; } int expand(int stat, int len, int k) { int tmp = stat, x, y; len += 4; k ^= 1; x = FX[k]; y = FY[k]; for (int i = 2; i < len; ++ i) { x += FX[tmp & 3]; y += FY[tmp & 3]; tmp >>= 2; if (!x && !y) return -1; } return (stat << 2 & ((1 << (len + len - 2)) - 1)) | k; } int calc_stat() { int head = 0, tail = 1, Visit[1 << 14] = {0}; memset(Stat, 0xFF, sizeof(Stat)); memset(Food_Stat, 0xFF, sizeof(Food_Stat)); for (int i = 3; i > 0; -- i) { int k = 0; while (Snake_Pos[i - 1][0] + FX[k] != Snake_Pos[i][0] || Snake_Pos[i - 1][1] + FY[k] != Snake_Pos[i][1]) ++ k; Queue[1] = Queue[1] << 2 | k; } Queue[1] <<= 2; Visit[Queue[1]] = true; while (head < tail) { ++ head; int s0 = Queue[head]; int snake_stat0 = s0 >> 2; int snake_len = s0 & 3; for (int k = 0; k < 4; ++ k) { int snake_stat1 = expand(snake_stat0, snake_len, k); if (snake_stat1 >= 0) { int s1 = (snake_stat1 & 0xFFF) << 2 | snake_len; if (!Visit[s1]) { Queue[++ tail] = s1; Visit[s1] = tail; } Stat[head][k] = Visit[s1]; } } for (int k = 0; k < 4; ++ k) { int snake_stat1 = expand(snake_stat0, snake_len + 1, k); if (snake_stat1 >= 0) { if (snake_len < 3) { int s1 = (snake_stat1 & 0xFFF) << 2 | (snake_len + 1); if (!Visit[s1]) { Queue[++ tail] = s1; Visit[s1] = tail; } Food_Stat[head][k] = Visit[s1]; } else { Food_Stat[head][k] = 0; } } } } return 0; } #define make_stat(x, y, ss, fs, wt) ((x) << 22 | (y) << 18 | (ss) << 7 | (fs) << 3 | (wt)) int bfs() { int head = 0, tail = 1; memset(Visit, 0, sizeof(Visit)); Queue[1] = make_stat(Snake_Pos[0][0], Snake_Pos[0][1], 1, (1 << Food_N) - 1, 0); Visit[Queue[1] >> 3] |= 1 << 0; while (head < tail) { int s0 = Queue[++ head]; int x0 = s0 >> 22 & 0xF, y0 = s0 >> 18 & 0xF, snake_stat0 = s0 >> 7 & 0x7FF, food_stat0 = s0 >> 3 & 0xF, wait_time0 = s0 & 7; if (!food_stat0 && !wait_time0) { Answer_Link = head; break; } if (wait_time0) { int s1 = make_stat(x0, y0, snake_stat0, food_stat0, wait_time0 - 1); if (!(Visit[s1 >> 3] & 1 << (wait_time0 - 1))) { Queue[++ tail] = s1; Visit[s1 >> 3] |= 1 << (wait_time0 - 1); Prec[tail] = head; } } else { for (int k = 0; k < 4; ++ k) { int x1 = x0 + FX[k], y1 = y0 + FY[k], snake_stat1 = Stat[snake_stat0][k], food_stat1 = food_stat0, wait_time1 = abs(Map[x1][y1] - Map[x0][y0]); if (!Map[x1][y1]) continue; if (Food_Map[x1][y1] && food_stat0 & 1 << (Food_Map[x1][y1] - 1)) { snake_stat1 = Food_Stat[snake_stat0][k]; food_stat1 ^= 1 << (Food_Map[x1][y1] - 1); } else { snake_stat1 = Stat[snake_stat0][k]; } if (snake_stat1 < 0) continue; int s1 = make_stat(x1, y1, snake_stat1, food_stat1, wait_time1); if (!(Visit[s1 >> 3] & 1 << wait_time1)) { Queue[++ tail] = s1; Visit[s1 >> 3] |= 1 << wait_time1; Prec[tail] = head; } } } } return 0; } int calc_answer() { int p1 = Answer_Link; Answer_Time = Answer_N = 0; while (p1 > 1) { ++ Answer_Time; int p0 = Prec[p1]; int wait_time = Queue[p0] & 7; if (!wait_time) { int x0 = Queue[p0] >> 22 & 0xF, y0 = Queue[p0] >> 18 & 0xF, x1 = Queue[p1] >> 22 & 0xF, y1 = Queue[p1] >> 18 & 0xF; int k = 0; while (x0 + FX[k] != x1 || y0 + FY[k] != y1) ++ k; Answer_C[Answer_N ++] = FC[k]; } p1 = p0; } for (int i = 0; i < (Answer_N >> 1); ++ i) { char tmp = Answer_C[i]; Answer_C[i] = Answer_C[Answer_N - i - 1]; Answer_C[Answer_N - i - 1] = tmp; } return 0; } int solve() { calc_stat(); bfs(); calc_answer(); return 0; } int output() { if (Answer_Link) { printf("%d\n", Answer_Time); for (int i = 0; i < Answer_N; ++ i) printf("%c", Answer_C[i]); printf("\n"); } else { printf("No solution.\n"); } return 0; } int main() { freopen("snake.in", "r", stdin); freopen("snake.out", "w", stdout); input(); solve(); output(); return 0; }
相关文章推荐
- 【bzoj2284】【SDOI2011】贪吃蛇【搜索】【位运算】【卡常大法好】
- BZOJ.2246.[SDOI2011]迷宫探险(DP 记忆化搜索 概率)
- BZOJ2243: [SDOI2011]染色
- [SDOI2011][BZOJ2286] 消耗战|虚树|树型dp|树上倍增LCA
- BZOJ2243: [SDOI2011]染色 树链剖分
- bzoj2242 [SDOI2011]计算器
- bzoj2243 [SDOI2011]染色
- BZOJ 2286 [Sdoi2011]消耗战(虚树+树形DP)
- BZOJ 2243 SDOI 2011染色
- BZOJ 2241: [SDOI2011]打地鼠
- BZOJ 2242: [SDOI2011]计算器
- bzoj2242 [SDOI2011]计算器(KSM+扩欧+bsgs)
- bzoj 3611: [Heoi2014]大工程 && bzoj 2286: [Sdoi2011消耗战
- BZOJ 2243: [SDOI2011]染色 [树链剖分+细节]【数据结构】
- 【bzoj2243】【sdoi2011】染色【树链剖分】
- BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca
- [BZOJ2282][Sdoi2011]消防(二分+贪心)
- 【费用流】【bzoj 2245】: [SDOI2011]工作安排
- 【bzoj2243】[SDOI2011]染色
- bzoj2243【SDOI2011】染色