BZOJ1054[HAOI]移动玩具|状态压缩SPFA

Description

在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到某人心中的目标状态。

Input

前4行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具。接着是一个空行。接下来4行表示玩具的目标状态,每行4个数字1或0,意义同上。

Output

一个整数,所需要的最少移动次数。

Sample Input

1111
0000
1110
0010

1010
0101
1010
0101

Sample Output

4





题解请见代码!

#include
#include
#include
#include

using namespace std;

bool vis[1<<17];
int st,en,num,tot,MAXN;
int shu[1<<17],dis[1<<17],h[1<<17];
char s[6];

struct Edge{
	int u,v,w,next;
}e[1001000];

void add(int u,int v,int w) {
	e[++tot].u=u;
	e[tot].v=v;
	e[tot].w=w;
	e[tot].next=h[u];
	h[u]=tot;
}

void spfa() {//spfa
	queue q;
	memset(dis,0x3f,sizeof(dis));
	vis[st]=1;
	dis[st]=0;
	q.push(st);
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=h[u];i;i=e[i].next) {
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w) {
				dis[v]=dis[u]+e[i].w;
				if(!vis[v]) {
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
}

void init(){
	int i,j;
	for(i=0;i<4;++i) {
		scanf("%s",s);
		for(j=0;j<4;++j){
			if(s[j]=='1'){
				num++;//总共1数
				st+=1<<(i*4+j);//st为初始状态数
			}
		}
	}
	getchar();
	for(i=0;i<4;++i) {
		scanf("%s",s);
		for(j=0;j<4;++j){
			if(s[j]=='1') {
				en+=1<<(i*4+j);//en为目标状态数
			}
		}
	}
	for(i=0;i<16;++i) shu[1<>1;//可以右移一位,l为移动后的状态
					if(!(l&i)){//如果状态合法,即在l与i中没有两个相同位置都是1
						add(i,i-(j&(-j))+l,1);//建边
					}
				}
				if(shu[j&(-j)]%4!=0){//如果这个1在位置数组里%4!=0就表示它不在最右边
					int l=(j&(-j))<<1;
					if(!(l&i)) {
						add(i,i-(j&(-j))+l,1);
					}
				}
				if(shu[j&(-j)]/4<3){////如果这个1在位置数组里/4!<3就表示它不在最下边
					int l=(j&(-j))<<4;//往上走
					if(!(l&i)) {
						add(i,i-(j&(-j))+l,1);
					}
				}
				if(shu[j&(-j)]/4!=0) {//如果这个1在位置数组里/4!=0就表示它不在最上边
					int l=(j&(-j))>>4;//往下走
					if(!(l&i)) {
						add(i,i-(j&(-j))+l,1);
					}
				}
			}
		}
	}
	spfa();
	printf("%d",dis[en]);
}

int main(){
	init();
//	while(1);
}
/*
1111
0000
1110
0010

1010
0101
1010
0101
*/


你可能感兴趣的:(BZOJ题解)