hdu 3006 状态压缩

动态规划之状态压缩,实际就是灵活运用位运算。

一个数,转换成2进制,其每一个位的0或者1,都好比是一个开关。这样可以通过灵活的位操作来简化复杂的状态转换。

例如:数字 7,二进制为 111。111 的状态,可以通过 110 | 001 , 101 | 010 , 011 | 100 这三种情况


如何获得一个数的二进制最后一个1的位置?公式: x & (-x)。例如, (10) & (-10) = 2,二进制:(1010) & (-0110) = 0010


这道题,就是将集合里的包含的数,用位来表示,例如,某集合A为 {1,4,7},就可以用 01001001 来表示,位为1的,就表示集合有这个元素。集合B为{3, 7},表示为01000100,那么A和B两个集合合并的结果就是:01001001 | 01000100 = 01001100 ,即新的集合为{3, 4, 7}。很巧妙是吧,看下面的代码,自己慢慢琢磨体会。


#include "stdio.h"
#include "string.h"

int set[1<<14];

void main(){
	int n, m;
	int z, i, j, k, w, sum;

	freopen("in.txt", "r", stdin);

	while(scanf("%d %d", &n, &m)!=EOF){
		memset(set, 0, sizeof(set));
		for(i=0; i<n; i++){
			scanf("%d", &k);
			w = 0;
			for(j=0; j<k; j++){
				scanf("%d", &z);
				w += 1<<(z-1);
			}
			set[w] = 1;  //w状态的集合,标记为1,表示已经有了

			for(j=1; j<1<<14; j++){
				if(set[j]) //若j状态的集合有了,那么将新来的w集合与j集合合并,就可以产生w|j集合。
					set[w|j] = 1;
			}
		}
		
		sum = 0;
		for(j=1; j<1<<14; j++){
			if(set[j])  //最后计算所有j状态的集合的总数
				sum++;
		}

		printf("%d\n", sum);
	}
	
}


上述程序的过程为:

假如A,B,C,D....这几个集合,依次输入

输入A ,则A集合有了。 //A

输入B,则B集合有了,然后B去和其他集合合并,现在只有一个A集合,那么合并产生A|B。 // A, B, A|B

输入C,则C集合有了,然后C去和其他集合合并,现在有3个其他的集合,那么合并产生……  // A, B, A|B, C,  A|C, B|C, A|B|C

输入D,则……  //A, B, A|B, C, A|C, B|C, A|B|C, D, A|D, B|D, A|B|D, C|D, A|C|D, B|C|D, A|B|C|D

同理,…… 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值