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*不僅代碼短,跑的還很快...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章