poj 1903 meet in the middle部分枚舉思想

題意:給出N個字符串(1 <= N <= 24),問最多可以找出多少個字符串,使得這些字符串中所有相同字符的個數和均爲偶數,並輸出是哪些字符串。


思路:把字符串分爲兩部分,分別枚舉狀態,並在map中查找後半部分的狀態是否在前半部分出現,從而達到枚舉全部子集的效果。

時間複雜度爲:O(2^(n/2) * log n)


#include <cstdio>
#include <map>
using namespace std;

const int N = 1000086, M = 33;
char s[N];
int st[M];
map<int, int> Map;

inline int count_bits(int x){ return __builtin_popcount(x); }

int main()
{
	#ifdef LOCAL
	freopen("in", "r", stdin);
	#endif // LOCAL
	int n;
	while(~scanf("%d", &n)) {
		Map.clear();
		for(int i = 0; i < n; ++i) {
			scanf("%s", s);
			st[i] = 0;
			for(int j = 0; s[j]; ++j) {
				st[i] ^= (1 << (s[j] - 'A'));
			}
		}
		int nn = n >> 1, nn1 = n - nn;
		for(int i = 0; i < (1 << nn); ++i) {
			int x = 0;
			for(int j = 0; j < nn; ++j) {
				if(i & (1 << j)) {
					x ^= st[j];
				}
			}
			if(!Map[x] || count_bits(i) > count_bits(Map[x])) Map[x] = i;
		}
		int ans = 0;
		for(int i = 0; i < (1 << nn1); ++i) {
			int x = 0;
			for(int j = 0; j < nn1; ++j) {
				if(i & (1 << j)) {
					x ^= st[j + nn];
				}
			}
			if((Map[x] || x == 0) && count_bits(Map[x]) + count_bits(i) > count_bits(ans)) ans = (i << nn) | Map[x];
		}
		printf("%d\n", count_bits(ans));
		bool flag = 0;
		for(int i = 0; i < n; ++i) {
			if((1 << i) & ans) {
				printf("%s%d", flag ? " " : "", i + 1);
				flag = 1;
			}
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章