UVA 687 - Lattice Practices(暴力枚举+位运算)

  Lattice Practices 

Once upon a time, there was a king who loved beautiful costumes very much. The king had a special cocoon bed to make excellent cloth of silk. The cocoon bed had 16 small square rooms, forming a 4$\times$4 lattice, for 16 silkworms. The cocoon bed can be depicted as follows:

The cocoon bed can be divided into 10 rectangular boards, each of which has 5 slits:

Note that, except for the slit depth, there is no difference between the left side and the right side of the board (or, between the front and the back); thus, we cannot distinguish a symmetric board from its rotated image as is shown in the following:

Slits have two kinds of depth, either shallow or deep. The cocoon bed should be constructed by fitting five of the boards vertically and the others horizontally, matching a shallow slit with a deep slit.


Your job is to write a program that calculates the number of possible configurations to make the lattice. You may assume that there is no pair of identical boards. Notice that we are interested in the number of essentially different configurations and therefore you should not count mirror image configurations and rotated configurations separately as different configurations.


The following is an example of mirror image and rotated configurations, showing vertical and horizontal boards seperately, where shallow and deep slits are denoted by `1' and `0' respectively.

Notice that a rotation may exchange positions of a vertical board and a horizontal board.

Input 

The input consists of multiple data sets, each in a line. A data set gives the patterns of slits of 10 boards used to construct the lattice. The format of a data set is as follows:

xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx

Each x is either `0' or `1'. `0' means a deep slit, and `1' a shallow slit. A block of five slit descriptions corresponds to a board. There are 10 blocks of slit descriptions in a line. Two adjacent blocks are separated by a space.


For example, the first data set in the Sample Input means the set of the following 10 boards:

The end of the input is indicated by a line consisting solely of three characters ``END''.

Output 

For each data set, the number of possible configurations to make the lattice from the given 10 boards should be output, each in a separate line.

Sample Input 

10000 01000 00100 11000 01100 11111 01110 11100 10110 11110
10101 01000 00000 11001 01100 11101 01110 11100 10110 11010
END

Sample Output 

40
6

题意:给10块床坂,求可以拼出的种数,旋转对称算一种。

思路:每一块可以用一个2进制数表示,并且拼图是不重复的。所以只要开一个32的数组就能存放拼图了。暴力枚举。枚举5块正放逆放,然后另外5快去判断能不能组成,一开始想总情况直接除以8,结果一直WA,后面改成用SET保存下找到过的方法的对应的8种方法,就过了。。哎,写得很搓,卡了两天了。。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <set>
using namespace std;

const int zhuan[25] = {20, 15, 10, 5, 0, 21, 16, 11, 6, 1, 22 ,17, 12, 7, 2, 23, 18, 13, 8, 3, 24, 19, 14, 9, 4};
const int dui[25] = {4, 3, 2, 1, 0, 9, 8, 7, 6, 5, 14, 13, 12, 11, 10, 19, 18, 17, 16, 15, 24, 23, 22, 21, 20};
const int N = 20;

char str[N], sb[30], sbb[30];
int way[N], ans, save[N], saven, v[32], z[32];
set<string> state;
void zh(char *a) {
	char save[30];
	for (int i = 0; i < 25; i ++)
		save[i] = a[zhuan[i]];
	save[25] = '\0';
	strcpy(a, save);
}

void dc(char *a) {
	char save[30];
	for (int i = 0; i < 25; i ++)
		save[i] = a[dui[i]];
	save[25] = '\0';
	strcpy(a, save);
}

int hash(char *s) {
	int sum = 0;
	for (int i = 0; i < 5; i ++)
		if (s[i] == '1') sum = sum * 2 + 1;
		else sum *= 2;
	return sum;
}

void init() {
	state.clear();
	memset(sb, 0, sizeof(sb));
	memset(sbb, 0, sizeof(sbb));
	memset(v, 0, sizeof(v));
	v[hash(str)]++; v[z[hash(str)]]++;
	for (int i = 1; i < 10; i++) {
		scanf("%s", str);
		v[hash(str)]++; v[z[hash(str)]]++;
	}
}

bool find(int s) {
	if (v[s]) {
		v[s]--; v[z[s]]--;
		save[saven++] = s;
		return true;
	}
	return false;
}

bool judge() {
	for (int i = 4; i >= 0; i --) {
		int s = 0;
		for (int j = 0; j < 5; j ++) {
			if ((way[j] & (1<<i))) s = (s<<1);
			else s = (s<<1) + 1;
		}
		if (!find(s))
			return false;
	}
	return true;
}

void tra() {
	for (int i = 4; i >= 0; i --) {
		for (int j = 0; j < 5; j ++) {
			if ((way[j] & (1<<i))) sb[(4 - i) * 5 + j] = '1';
			else sb[(4 - i) * 5 + j] = '0';
		}
	}
}

void cao() {
	for (int i = 0; i < 25; i ++)
		if (sb[i] == '1') sbb[i] = '0';
		else sbb[i] = '1';
}

void IS() {
	for (int i = 0; i < 2; i ++) {
		dc(sb);
		for (int j = 0; j < 4; j ++) {
			zh(sb);	
			cao();
			state.insert(sbb);
			state.insert(sb);	
		}
	}
}

void dfs(int m) {
	if (m == 5) {
		saven = 0;
		if (judge()) {
			tra();
			if (state.find(sb) == state.end()) {
				IS();
				ans++;
			}
		}
		for (int j = 0; j < saven; j ++) {
			v[save[j]]++; v[z[save[j]]]++;
		}
		return;
	}
	for (int i = 0; i < 32; i ++) {
		if (v[i] == 0) continue;	
		v[i]--; v[z[i]]--;
		way[m] = i;
		dfs(m + 1);
		v[i]++; v[z[i]]++;
	}
}

int solve() {
	ans = 0;
	dfs(0);
	return ans;
}

int tra(int num) {
	int sum = 0;
	for (int i = 4; i >= 0; i--) {
		if (num >= (1<<i)) {
			num -= (1<<i);
			sum += (1<<(4-i));
		}
	}
	return sum;
}

void z_table() {
	for (int i = 0; i < 32; i ++)
		z[i] = tra(i);
}

int main() {
	z_table();
	while (~scanf("%s", str) && str[0] != 'E') {
		init();
		printf("%d\n", solve());
	}
	return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值