利用二进制枚举和状态压缩

利用二进制来表达选择的状态

例题:
话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

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

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	int ans=0;
	for(int i=0;i<(1<<14);++i){
	int tot_1=0;
	int tot_0=0;
	int num=2;
	for(int j=0;j<14;++j){
		if(i&(1<<j)){//判断 i从右数第j+1位是否为1 
			tot_1++;
			num=num*2;
		}
		else {
			tot_0++;
			num-=1;
		}
	}
	if(num==1 && tot_1==5 && tot_0==9){
		ans++;
	}
}
	cout<<ans<<endl;
	return 0;
}


x星球的盛大节日为增加气氛,用30台机光器一字排开,向太空中打出光柱。
安装调试的时候才发现,不知什么原因,相邻的两台激光器不能同时打开!
国王很想知道,在目前这种bug存在的情况下,一共能打出多少种激光效果?
显然,如果只有3台机器,一共可以成5种样式,即:
全都关上(sorry, 此时无声胜有声,这也算一种)
开一台,共3种
开两台,只1种
30台就不好算了,国王只好请你帮忙了。

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
long long ans;
int main(){
  for(int i=0;i<(1<<30);i++){
      int flag=1;
      for(int j=1;j<30;j++){
          if(i&(i>>1)){//没有相邻的1
              flag=0;
              break;
          }
      }
              ans+=flag;
  }
    //ans=2178309;
    cout<<ans;
  return 0;
}
 

状态压缩

当元素数量比较小(不超过20)时,可以使用状态压缩
比如5个元素a,b,c,d,e 可以分别用1,2,4,8,16表示 则集合{b,c,d}可以用(01110)=14表示,这种方法经常使用与动态规划中
如果用传统的动态规划作法对5个元素则需要至少开5维数组,利用状态压缩则可以压缩进一维数组里。但同时注意这种方法并没有优化空间复杂度,只是相对的容易写出代码.

n个人在做传递物品的游戏,编号为1-n。

游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。

即物品只能经过同一个人一次,而且每次传递过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;

求当物品经过所有n个人后,整个过程的总代价是多少。

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
int a[20][20];
int dp[1 << 16][20];
int main(){
	memset(dp,0x3f,sizeof(dp));
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
		dp[1 << i][i]=0;
		for(int j=0;j<n;j++){
			cin>>a[i][j];
		}
	}
	for(int i=0;i<(1 << n);i++){
		for(int j=0;j<n;j++){
			if(i & (1<<j)){
				for(int k=0;k<n;k++){
					if(!(i&(1<<k))){
						dp[i | 1<<k][k]=min(dp[i|1<<k][k],dp[i][j]+a[j][k]);
					}
				}
			}
		}
	}
	int ans=INF;
	for(int i=0;i<n;i++){
		ans=min(ans,dp[(1<<n)-1][i]);
	}
	cout<<ans<<endl;
  return 0;
}


//  freopen("testdata.in", "r", stdin);



posted @ 2020-11-04 15:01  一个经常掉线的人  阅读(110)  评论(0编辑  收藏  举报