李白打酒之全排列


一、问题描述

话说大诗人李白,一生好饮。幸好他从不开车。一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:无事街上走,提壶去打酒。逢店加一倍,遇花喝一斗。这一路上,他一共遇到店5次,遇到花10次,已知最后遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能的方案的个数(包含题目给出的)。

注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。

二、解题思路

用1代表遇到花,0代表遇到店。最后一位固定为1,前面14位必须有9个1,5个0。
元素不变,顺序可变,不同的排列顺序对应一种可能的方案,可以将解空间看成是14个数的排列问题。但是存在重复的元素,应该采用可以处理重复元素的全排列方法。

三、相关算法

1.交换法

代码如下(示例):

#include <bits/stdc++.h>
using namespace std;
int number=0;
int a[20]={0,0,0,0,0,1,1,1,1,1,1,1,1,1,1};
bool check(){
	int res=2;
	for(int i=0;i<15;i++){
		if(a[i]==0){
			res*=2;
		}else{
			res-=1;
		}
	}
	if(res==0){
		return true;
	}else{
		return false;
	}
}
void f(int p,int a[],int n){
	if(p==n){
		if(check()){
			number++;
		}
		return;
	} 
	for(int i=p;i<n;i++){
		if(i>p&&a[i]==a[i-1]){
			continue;
		}
		swap(a[i],a[p]);
		f(p+1,a,n);
		swap(a[i],a[p]);
	}
} 
int main(){
	f(0,a,14);
	cout<<number<<endl;
	return 0;
}

2.抽取法

代码如下(示例):

#include <bits/stdc++.h>
using namespace std;
int number=0;
int a[20]={0,0,0,0,0,1,1,1,1,1,1,1,1,1,1};
int b[20];
int vis[20]={0};
bool check(){
	int res=2;
	for(int i=0;i<14;i++){
		if(b[i]==0){
			res*=2;
		}else{
			res-=1;
		}
	}
	res-=1;
	if(res==0){
		return true;
	}else{
		return false;
	}
}
void f(int a[],int n,int b[],int p){
	if(p==n){
		if(check()){
			number++;
		}
		return;
	} 
	for(int i=0;i<n;i++){
		if(i>0&&a[i]==a[i-1]&&!vis[i-1]){
			continue;
		}
		if(!vis[i]){
			b[p]=a[i];
			vis[i]=1;
			f(a,n,b,p+1);
			vis[i]=0;
		}
	}
} 
int main(){
	f(a,14,b,0);
	cout<<number<<endl;
	return 0;
}

3.使用next_permutation求解

代码如下(示例):

#include <bits/stdc++.h>
using namespace std;
int number=0;
int a[20]={0,0,0,0,0,1,1,1,1,1,1,1,1,1,1};
bool check(){
	int res=2;
	for(int i=0;i<15;i++){
		if(a[i]==0){
			res*=2;
		}else{
			res-=1;
		}
	}
	if(res==0){
		return true;
	}else{
		return false;
	}
} 
int main(){
	do{
		if(check()){
			number++;
		}
	}while(next_permutation(a,a+14));
	cout<<number<<endl;
	return 0;
}

四、运算结果

答案:14

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值