[代码备份]poj1324--未完成

备份备份.写不来状态压缩压缩压缩缩缩缩缩缩缩缩
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int MAX = 25;

/* N:1, E:2, S:3, W:4 */
int Move[5][2] = {0,0, -1,0, 0,1, 1,0, 0,-1};
int Move_left[5][2] = {0,0, 0,-1, -1,0, 0,1, 1,0};
int Move_right[5][2] = {0,0, 0,1, 1,0, 0,-1, -1,0};
int way_left[5] = {0, 4, 1, 2, 3};
int way_right[5] = {0, 2, 3, 4, 1};

struct Point {
	int x, y;
	Point(){}
	Point(int a, int b):x(a), y(b) {}
	bool operator==(const Point& B)const {
		return x == B.x && y == B.y;
	}
} E(1, 1); //E:终点

/* 根据蛇身两个点,返回第二个点相对第一个点的相对位置 */
/* N:1 E:2 S:3 W:4 */
int Next(int x, int y, int tx, int ty) {
	if (x == tx) {
        if (ty > y) return 2;
        return 4;
	} else {
		if (tx > x) return 3;
		return 1;
	}
}

struct Snake:public Point {
	int to; //x,y,to -> head
	int steps; //步数
    int status; //状态,每个状态对应一个至多7位的4进制数,为0~4^8-1;
    /* 状态描述为头坐标,然后是身子的每个点与上一个点的相对位置 */
    /* 实际上只需要3个方向 */
    /* 长度就不在这里描述了,反正题目会给出来 */
    Snake() {status = 0;}
    /* 获得蛇的当前状态 */
    vector<Point> getStatus(void) {
		/* 解码,返回蛇身子的每个点坐标 */
		vector<Point> res;
		Point p(x, y);
		res.push_back(p);
		while (status) {
			int ft = status % 5;
            status /= 5;
			p.x += Move[ft][0], p.y += Move[ft][1];
			res.push_back(p);
		}
		return res;
    }//getStatus
    /* 设置状态,根据pos指定的点坐标,还原蛇的状态. */
    void setStatus(vector<Point> pos) {
        status = 0;
        x = pos[0].x, y = pos[0].y;
        int &t = status, tmp; ///啦啦啦
		t = 0;
		for (int i = pos.size()-1; i > 0; --i) {
			tmp = Next(pos[i-1].x, pos[i-1].y, pos[i].x, pos[i].y);
			t *= 5;
			t += tmp;
		}
		tmp = Next(pos[0].x, pos[0].y, pos[1].x, pos[1].y);
        to = (tmp+2)%4 == 0 ? 4 : (tmp+2)%4;
    }
    /* 蛇前进一步 */
    void Forward(void) {
        /* 蛇头前进一步,身子呢?身子其实奏是走到它前面那个点就OK了 */
        vector<Point> pos = getStatus();
        for (int i = pos.size()-1; i > 0; --i) {
			pos[i].x = pos[i-1].x, pos[i].y = pos[i-1].y;
        }
		pos[0].x += Move[to][0], pos[0].y += Move[to][1];
		setStatus(pos);
    }
    /* 向左走一步 */
    void Left(void) {
        /* 类同上述,蛇头左走一步,身子挪到前一个位置 */
        vector<Point> pos = getStatus();
        for (int i = pos.size()-1; i > 0; --i) {
			pos[i].x = pos[i-1].x, pos[i].y = pos[i-1].y;
        }
		pos[0].x += Move_left[to][0], pos[0].y += Move_left[to][1];
		setStatus(pos);
    }
    /* 向右走一步 */
    void Right(void) {
		vector<Point> pos = getStatus();
		for (int i = pos.size()-1; i > 0; --i) {
			pos[i].x = pos[i-1].x, pos[i].y = pos[i-1].y;
		}
		pos[0].x += Move_right[to][0], pos[0].y += Move_right[to][1];
		setStatus(pos);
    }
} snake;
int n, m, K, L;
bool Map[MAX][MAX];
bool vis[MAX][MAX][5];
vector<Point> body;

void exChange(void) {
    snake.x = body[0].x;
    snake.y = body[0].y;
    snake.steps = 0;
    int &t = snake.status, tmp; ///啦啦啦
    t = 0;
    for (int i = L-1; i > 0; --i) {
        tmp = Next(body[i-1].x, body[i-1].y, body[i].x, body[i].y);
        t *= 5;
        t += tmp;
    }
    tmp = Next(body[0].x, body[0].y, body[1].x, body[1].y); //召唤出第一节身子在头的甚么方向
    snake.to = (tmp+2)%4 == 0 ? 4 : (tmp+2)%4;//1->3, 2->4, 3->1, 4->2.第一节身子在头的南方,头就朝向北,其他方向类同
    //printf("way: %d\n", snake.to);
}

bool check(int x, int y) {
    return x > 0 && y > 0 && x <= n && y <= m
			&& Map[x][y];
}

bool judge(Snake s, int x, int y) {
    /* 题目说明是蛇头先动,完了后身子再前移.
     * 所以这里很关键,判据不能丢
     */
     Point p(x, y);
     vector<Point> tmp = s.getStatus();
     //printf("receive: %d,%d\n", x, y);
     //bool PRINT = (x == 5 && y == 2);
     //if (PRINT) puts("warning!......");
     for (int i = 0; i < tmp.size(); ++i) {
		//if (PRINT) {
			//printf("judge %d,%d...", tmp[i].x, tmp[i].y);
		//}
		if (tmp[i] == p) {
			//if (PRINT) printf("Failed\n");
			return false;
		}
		//if (PRINT) puts("ok");
     }
     return true;
}
/* BFS,每次压入一只蛇,包含了它的状态.搜下一层时其一不能撞到石头或越界,
 * 其二不能撞到身子,用judge函数来判断(二),用check函数来检查(一)
 */
int BFS(void) {
	memset(vis, false, sizeof(vis));
	Point tmp;
	queue<Snake> Q;
	Snake now, next;
    Q.push(snake); //初始
    while (!Q.empty()) {
        now = Q.front(); Q.pop();
		if (now == E) return now.steps;
        //枚举三个状态:蛇头向前,向左,向右
		/* forward */
		next = now; next.steps++;
		tmp.x = now.x + Move[next.to][0];
		tmp.y = now.y + Move[next.to][1];
		if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y][next.to] && judge(now, tmp.x, tmp.y)) {
			next.Forward();
			Q.push(next);
			//printf("Push1: (%d,%d,%d,%d)\n", next.x, next.y, next.to, next.steps);
			//getchar();
			vis[next.x][next.y][next.to] = true;
		}

		/* left */
		next = now; next.steps++;
		tmp.x = now.x + Move_left[now.to][0];
		tmp.y = now.y + Move_left[now.to][1];
		//puts("warning");
		//printf("%d,%d -> %d,%d\n", now.x, now.y, tmp.x, tmp.y);
		if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y][way_left[now.to]] && judge(now, tmp.x, tmp.y)) {
			//puts("flag2");
			//printf("now = %d,%d,%d\n", now.x, now.y, now.to);
			next.Left();
			Q.push(next);
			//printf("Push2: (%d,%d,%d,%d)\n", next.x, next.y, next.to, next.steps);
			//getchar();
			vis[next.x][next.y][next.to] = true;
		}

		/* right */
		next = now; next.steps++;
		tmp.x = now.x + Move_right[now.to][0];
		tmp.y = now.y + Move_right[now.to][1];
		if (check(tmp.x, tmp.y) && !vis[tmp.x][tmp.y][way_right[now.to]] && judge(now, tmp.x, tmp.y)) {
			next.Right();
			Q.push(next);
			//printf("Push3: (%d,%d,%d,%d)\n", next.x, next.y, next.to, next.steps);
			//getchar();
			vis[next.x][next.y][next.to] = true;
		}
		//static int _t = 0;
		//printf("%d\n", ++_t);
		//puts("flag");
    }
    return -1;
}
int main() {
	while (~scanf(" %d %d %d", &n, &m, &L) && L) {
		memset(Map, true, sizeof(Map));
		body.resize(L+1);
		for (int i = 0; i < L; ++i) {
			scanf(" %d %d", &body[i].x, &body[i].y);
		}
		scanf(" %d", &K);
		int x, y;
		for (int i = 0; i < K; ++i) {
			scanf(" %d %d", &x, &y);
			Map[x][y] = false;
		}
        exChange();
        static int cas = 0;
        printf("Case %d: %d\n", ++cas, BFS());
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值