BZOJ1085 [SCOI2005]骑士精神

题意:5x5的棋盘有12只黑马,12只白马,一个空位,移动采用国际象棋马的移动方法,要求最少步数移动到目标局面,如果步数大于15步,输出-1.

分析:

这是昨天比赛的第一题,比赛时我用的双向BFS+hash判重,A了,不幸在BZOJ上TLE,按照lyd神犇的话说,步数大于15步输出-1这种限制就是告诉你要用ID-DFS,这道题状态有些多,我们还需要加个A*优化(gzz神犇比赛时就写出来了,无限orz中...)

双向BFS+hash判重代码(TLE):

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
 
typedef long long ll;
typedef int sta[30];
const int p = 1000007, dx[] = {-2,-1,1,2,2,1,-1,-2}, dy[] = {-1,-2,-2,-1,1,2,2,1};
char s[10];
int T,x,y,hd[p],nxt[p],hdd[p],nxtt[p],d[1000000],dd[1000000];
sta st[1000000],stt[1000000], goal = {1,1,1,1,1,0,1,1,1,1,0,0,2,1,1,0,0,0,0,1,0,0,0,0,0};
 
int hash(sta &a) {
    int sum = 0;
    for(int i = 0; i < 5; i++)
    for(int j = 0; j < 5; j++)
        sum = (sum*3+a[i*5+j])%p;
    return sum;
}
bool in(int a) {
    int h = hash(st[a]);
    for(int i = hd[h]; i; i = nxt[i])
    if(!memcmp(st[i], st[a], sizeof st[a])) return false;
    nxt[a] = hd[h], hd[h] = a;
    return true;
}
int srch(int a) {
    int h = hash(stt[a]);
    for(int i = hd[h]; i; i = nxt[i])
    if(!memcmp(st[i], stt[a], sizeof stt[a])) return d[i];
    return -1;
}
bool in2(int a) {
    int h = hash(stt[a]);
    for(int i = hdd[h]; i; i = nxtt[i])
    if(!memcmp(stt[i], stt[a], sizeof stt[a])) return false;
    nxtt[a] = hdd[h], hdd[h] = a;
    return true;
}
 
int bfs() {
    int front = 1, rear = 2;
    while(front < rear) {
        sta &u = st[front];
        if(d[front] > 7) break;
        if(!memcmp(goal, u, sizeof u)) return d[front];
        for(int i = 0; i < 25; i++)
        if(u[i] == 2) {
            x = i/5, y = i%5;
            break;
        }
        for(int i = 0; i < 8; i++) {
            int xx = x+dx[i], yy = y+dy[i];
            if(xx >= 0 && xx < 5 && yy >= 0 && yy < 5) {
                sta &tmp = st[rear];
                memcpy(&tmp, &u, sizeof u);
                swap(tmp[x*5+y], tmp[xx*5+yy]);
                if(in(rear)) d[rear] = d[front]+1, rear++;
            }
        }
        front++;
    }
    return -1;
}
 
int bfs2() {
    int front = 1, rear = 2;
    memcpy(stt[1], goal, sizeof stt[1]);
    while(front < rear) {
        sta &u = stt[front];
        if(dd[front] > 7) break;
        int a = srch(front);
        if(~a) return a+dd[front];
        for(int i = 0; i < 25; i++)
        if(u[i] == 2) {
            x = i/5, y = i%5;
            break;
        }
        for(int i = 0; i < 8; i++) {
            int xx = x+dx[i], yy = y+dy[i];
            if(xx >= 0 && xx < 5 && yy >= 0 && yy < 5) {
                sta &tmp = stt[rear];
                memcpy(&tmp, &u, sizeof u);
                swap(tmp[x*5+y], tmp[xx*5+yy]);
                if(in2(rear)) dd[rear] = dd[front]+1, rear++;
            }
        }
        front++;
    }
    return -1;
}
 
int main() {
    scanf("%d", &T);
    while(T--) {
        memset(hd, 0, sizeof hd);
        memset(hdd, 0, sizeof hdd);
        for(int i = 0; i < 5; i++) {
            scanf("%s", s);
            for(int j = 0; j < 5; j++) {
                st[1][i*5+j] = s[j]-'0';
                if(s[j] == '*') st[1][i*5+j] = 2;
            }
        }
        int a = bfs();
        if(~a) printf("%d\n", a);
        else printf("%d\n", bfs2());
    }
    return 0;
}
ID-DFS+A*代码(AC):

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

const int dx[]={-2,-1,1,2,2,1,-1,-2}, dy[]={-1,-2,-2,-1,1,2,2,1};
char s[9];
int T,ok,x,y,k,a[5][5],goal[5][5]={{1,1,1,1,1},{0,1,1,1,1},{0,0,2,1,1},{0,0,0,0,1},{0,0,0,0,0}};

bool okk(int dep) {
	int cnt = 0;
	for(int i = 0; i < 5; i++)
	for(int j = 0; j < 5; j++)
	if(a[i][j] != goal[i][j]) {
		cnt++;
		if(cnt+dep > k) return false;
	}
	return true;
}
void dfs(int dep, int x, int y) {
	if(dep == k && !memcmp(a,goal,sizeof a)) {ok = 1; return;}
	for(int i = 0; i < 8; i++) if(!ok && dep < k) {
		int xx = x+dx[i], yy = y+dy[i];
		if(xx >= 0 && xx < 5 && yy >= 0 && yy < 5) {
			swap(a[x][y], a[xx][yy]);
			if(okk(dep)) dfs(dep+1, xx, yy);
			swap(a[x][y], a[xx][yy]);
		}
	}
}

int main() {
	scanf("%d", &T);
	while(T--) {
		for(int i = 0; i < 5; i++) {
			scanf("%s", s);
			for(int j = 0; j < 5; j++) if(s[j]=='*') x=i,y=j,a[i][j]=2; else a[i][j]=s[j]-'0';
		}
		ok = 0;
		for(k = 1; k <= 15; k++) {
			dfs(0, x, y);
			if(ok) {printf("%d\n", k); break;}
		}
		if(!ok) puts("-1");
	}
	return 0;
}
由上还可以看出ID-DFS+A*不仅代码短,跑的还很快...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值