BFS解决一般性的泊松分酒问题

BFS解决一般性的泊松分酒问题

  有一只装满8斤酒的瓶子和两只分别装5斤和3斤酒的空瓶,如何才能将这8斤酒分为两等份。这个问题规模小,手工就可以完成。那么更大规模和一般性的问题又如何解决呢? 

  通过广度优先搜索(BFS)对状态空间进行逐步搜索,若能找到答案,则为最少步数解,反之则无解。具体过程如下:

      设共有n个瓶子,最大容量分别为(x1,x2,...,xn),则共有(x1+1)(x2+1)...(xn+1)种可能的状态,搜索空间过于庞大。但考虑到瓶子的容量差,在倒酒的过程中不可能出现所有的情况。因此要对新加入图中的状态进行判断,即剪枝,如果新生成的状态是可行的,将其加入图中,反之将其舍弃。在广度优先搜索的过程中,使用一个队列Q存储新生成的状态,一个数组Visited存储出现过的状态。搜索过程如下所示

Step1. 将初始状态(x10,x20,...,xn0)加入到队列Q以及Visited数组中。

Step2. 将队列Q队头的状态出队列,找出Q可能生成的状态。

Step3. 判断新生成的状态是否为目标状态,若是,则停止搜索,若不是,继续执行Step4。

Step4. 判断新生成的状态是否位于Visited数组中,若已存在则跳过该状态判断下一状态。若未存在则将其加入到队列Q尾部,并加入到Visited数组中,并判断下一个状态。

Step4. 不断执行Step2Step3Step4,直到队列为空,停止程序,此时未找到可行的解,则该问题无解。

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

#define TRUE 1
#define FASLE 0
#define MAXSIZE 100000

typedef struct{
	int **rear,**front;
	int Queuelen;
}Queue;

void InitQueue(Queue &Q, int n){
	Q.rear = Q.front = (int**)malloc(sizeof(int*) * MAXSIZE);
	for(int i = 0; i < MAXSIZE; i++){
		Q.rear[i] = Q.front[i] = (int*)malloc(sizeof(int) * n);
	}
	Q.Queuelen = 0;
}

void EnQueue(Queue &Q,int* e){
	*(Q.rear++) = e;
}

void DeQueue(Queue &Q,int* &e){
	e = *(Q.front++);
}

int QueueEmpty(Queue Q){
	if(Q.front == Q.rear)
	    return TRUE;
	else
	    return FASLE;
}

void pour(const int* status, const int* volume, int i, int j,int* new_volume, int n){
	for(int k = 0; k < n; k++){
		new_volume[k] = status[k];
	}
	if(new_volume[i] + new_volume[j] <= volume[j]){
		new_volume[j] += new_volume[i];
		new_volume[i] = 0;
	}
	else{
		new_volume[i] -= (volume[j] - new_volume[j]);
		new_volume[j] = volume[j];
	}
}

int exist(int** visited, int* new_volume,int n, int num){
	int flag;
	for(int i = 0; i < num; i++){
		flag = 1;
		for(int j = 0; j < n; j++){
			if(visited[i][j] != new_volume[j]){
				flag = 0;
				break;
			}
		}
		if(flag)    break;
	}
	return flag;
}

void append(int** &visited, int &num, int* new_volume, int n){
	for(int i = 0; i < n; i++){
		visited[num][i] = new_volume[i];
	}
	num++;
}

int achieve(const int* target, const int* new_volume, int n){
	int flag = 1;
	for(int i = 0; i < n; i++){
		if(target[i] != new_volume[i]){
			flag = 0;
			break; 
		}
	}
	return flag;
}

void print(const int* current_volume, int* new_volume, int n){
	for(int i = 0; i < n - 1; i++){
		printf("%d,",current_volume[i]);
	}
	printf("%d",current_volume[n - 1]);
	
	printf("---");
	
	for(int i = 0; i < n - 1; i++){
		printf("%d,",new_volume[i]);
	}
	printf("%d\n",new_volume[n - 1]);
}

void copy_volume(const int* new_volume, int* copy, int n){
	for(int k = 0; k < n; k++){
		copy[k] = new_volume[k];
	}
}

void BFS(int* volume, int* current_volume, int n, int* target){
	Queue Q;
	InitQueue(Q,n);
    EnQueue(Q, current_volume);
	int num = 0;
	int** visited;
	visited = (int**)malloc(sizeof(int*) * MAXSIZE);
	for(int i = 0; i < MAXSIZE; i++){
		visited[i] = (int*)malloc(sizeof(int) * n);
	}
	append(visited, num, current_volume, n);
	
	int* status = (int*)malloc(sizeof(int) * n);
	int* new_volume = (int*)malloc(sizeof(int) * n);
	int layer = 0;
	int* copy;
	int qlen[MAXSIZE]; 
	qlen[layer] = 1;
	int achieved = 0;
	
	while(!QueueEmpty(Q)){
		DeQueue(Q, status);
		for(int i = 0; i < n; i++){
			if(status[i] != 0){
				for(int j = 0; j < n; j++){
					if(j == i){
						//j--;
						continue;
					}
					
					if(status[j] == volume[j])    continue;
					
					pour(status, volume, i, j, new_volume, n);
					
					copy = (int*)malloc(sizeof(int) * n);
					copy_volume(new_volume, copy, n);
					if(exist(visited, copy, n, num))    continue;
					else{
						print(status, copy, n);
						if(achieve(target, new_volume, n)){
							printf("已找到答案!    ");
							printf("当前第%d层--------------------------\n",layer + 1);
							system("pause");
							achieved = 1;
						}    

						append(visited, num, copy, n);
						EnQueue(Q, copy);
					}
				}
			}
		}
		
		qlen[layer]--;
		
		if(!qlen[layer]){
			printf("第%d层遍历完毕--------------------------\n",layer + 1);
		    layer++;
		    qlen[layer] = Q.rear - Q.front;
		}
	}
	if(!achieved)    printf("未找到答案!    ");
	printf("搜索完毕\n***************************************\n\n"); 
}

int main(){
	int n;
	
	while(1){
		printf("请输入瓶子个数\n"); 
		scanf("%d",&n);
		int* volume;
		int* current_volume;
	    int* target;
	    target = (int*)malloc(sizeof(int) * n);
	    volume = (int*)malloc(sizeof(int) * n);
	    current_volume = (int*)malloc(sizeof(int) * n);
		int step = 0;
		
		printf("请输入各个瓶子的最大容量\n"); 
		for(int i = 0; i < n; i++){
			scanf("%d",&volume[i]);
		}
		printf("请输入各个瓶子的当前容量\n"); 
		for(int i = 0; i < n; i++){
			scanf("%d",¤t_volume[i]);
		}	
		printf("请输入各个瓶子的目标容量\n"); 
		for(int i = 0; i < n; i++){
			scanf("%d",&target[i]);
		}		
		
		BFS(volume, current_volume, n, target);
	}
	
	return 0;
} 
/*
3
8 5 3
8 0 0
4 4 0
*/







评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值