UVa321

对每一个状态进行遍历,用door来表示当前所在的房间,state[10]表示各个房间的开关情况,每次进行一步移动

总状态为10*2^10.用hash来判重。用一个状态数组flag来记录每一次是进行的什么操作。最终状态为所在房间为r,只有r房的灯开着的。

每次只考虑一步就行了,从小到大的开。一开始考虑复杂了,考虑到可能开一盏灯,然后还要从控制中选一盏,或者两盏灯等等。其实每次只要一步,这些开多盏灯的状态都可以从一次开一盏,一次开一盏的状态衍生出来。最近做了很多的搜索。貌似解答树类型的都用深搜,隐式图类型的都用广搜。注意坑爹的是r=1的时候要输出0步。被这坑了N久的时间.....

AC代码:

#include<iostream>
#include<cstring>
using namespace std;
const int MaxSize=20000;
const int HashTable=10007;
struct Node{
	int door,fa,dist;
	int to_do;
	int state[12];
};
int head[HashTable],Next[MaxSize];
Node st[MaxSize];
int flag[MaxSize];
int Maps[20][20];
int final_state[12];
int Links[20][20],have_find,r,d,s;
void print_path(int fa){
	if(st[fa].fa!=-1)
		print_path(st[fa].fa);
    if(flag[fa]==1){
	    cout << "- Move to room " << st[fa].to_do << ".\n";
    }
    if(flag[fa]==2){
	    cout << "- Switch off light in room " << st[fa].to_do << ".\n";
    }
    if(flag[fa]==3){
	   	cout << "- Switch on light in room " << st[fa].to_do << ".\n";
	}
}
int Hash(int a[]){
	int i,v;
	for(i=1,v=0;i<=10;i++){
		v=(v<<1)+a[i];
	}
	return v%HashTable;
}
bool try_to_insert(int s){
	int h=Hash(st[s].state);
	int u=head[h];
	while(u){
		if(memcmp(st[u].state,st[s].state,sizeof(st[u].state))==0&&st[u].door==st[s].door)
			return false;
		u=Next[u];
	}
	Next[s]=head[h];
	head[h]=s;
	return true;
}
int bfs(void){
	int front=1,rear=2,i;
	st[1].door=1;
	st[1].fa=-1;
	st[1].dist=0;
	st[1].state[1]=1;
	final_state[r]=1;
	try_to_insert(1);
	while(front<rear){
		Node &now=st[front];
		if(memcmp(now.state,final_state,sizeof(final_state))==0&&now.door==r){
			have_find=1;
			return front;
		}
		for(i=1;i<=r;i++){
			if(Maps[now.door][i]&&now.state[i]){
				memcpy(st[rear].state,now.state,sizeof(now.state));
				st[rear].door=i;
				st[rear].fa=front;
				st[rear].dist=now.dist+1;
				st[rear].to_do=i;
				flag[rear]=1;
				if(try_to_insert(rear))
					rear++;
			}
		}
		for(i=1;i<=r;i++){
			if(Links[now.door][i]&&i!=now.door){
				memcpy(st[rear].state,now.state,sizeof(now.state));
				st[rear].door=now.door;
				st[rear].dist=now.dist+1;
				st[rear].fa=front;
				if(now.state[i]==1){
					st[rear].state[i]=0;
					st[rear].to_do=i;
					flag[rear]=2;
					if(try_to_insert(rear))
						rear++;
				}
				else{
					st[rear].state[i]=1;
					st[rear].to_do=i;
					flag[rear]=3;
					if(try_to_insert(rear))
						rear++;
				}
			}
		}
		front++;
	}
	have_find=0;
	return 0;
}
int main()
{
	int i,do1,do2,case_num=1,state_num;
	while(cin>>r>>d>>s,(r||d||s)){
		memset(final_state,0,sizeof(final_state));
		memset(Maps,0,sizeof(Maps));
		memset(Links,0,sizeof(Links));
		memset(head,0,sizeof(head));
		have_find=0;
		for(i=1;i<=d;i++){
			cin >> do1 >> do2;
			Maps[do1][do2]=Maps[do2][do1]=1;
		}
		for(i=1;i<=s;i++){
			cin >>do1 >> do2;
			Links[do1][do2]=1;
		}
		state_num=bfs();
		cout << "Villa #" << case_num << endl;
		if(st[state_num].dist!=0)
		cout << "The problem can be solved in "<<st[state_num].dist << " steps:" << endl;
		case_num++;
		if(r==1)
			cout << "The problem can be solved in 0 steps:\n";
		if(have_find){
			print_path(state_num);
			cout << endl;
		}
		else{
			cout << "The problem cannot be solved." << endl;
			cout << endl;
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值