poj 1222 EXTENDED LIGHTS OUT
开关只有两种方案 按和不按,按两次相当于关
只用枚举第一排开关的按法即可,剩下的行为使上一排的灯全部关闭,按法可以确定,并且是唯一的。
最后检查最后一行是否都为0,都为0为可行的方案。 用位运算来实现。
#include <iostream> #include <stdio.h> #include <cstring> using namespace std; char ol[5], l[5], r[5]; int t; int getBit(char c, int i) { return 1 & (c>>i); } void setBit(char &c, int i, int v) { if (v) { c |= (1 << i); } else c &= ~(1 << i); } void FlipBit(char &c, int i) { c ^= (1 << i); } void output() { cout << "PUZZLE #" << t << endl; for (int i = 0; i < 5; i++) { for (int j = 0; j < 6; j++) { cout << getBit(r[i], j); if (j < 5) cout << " "; } cout << endl; } } int main() { //freopen("1.txt", "r", stdin); int T; cin >> T; for (t = 1; t <= T; t++) { for (int i = 0; i < 5; i++) for (int j = 0; j < 6; j++) { int s; cin >> s; setBit(ol[i], j, s); } for (int n = 0; n < 64; n++) { //枚举第一列方案0~2^6-1 memcpy(l, ol, sizeof(ol)); int switchs = n; //当前行的开关状态 for (int i = 0; i < 5; i++) { r[i] = switchs; for (int j = 0; j < 6; j++) { if (getBit(switchs, j)) { if (j > 0) FlipBit(l[i], j-1); FlipBit(l[i], j); if (j < 5) FlipBit(l[i], j+1); } } if (i < 4) l[i+1] ^=switchs; switchs = l[i]; //i+1行灯的状态由第i行灯的状态决定 } if (l[4] == 0) { output(); break; } } } return 0; }
特殊密码锁
描述
有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。
然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。
当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。
输入两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。输出至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。
样例输入
011 000
样例输出
1
类似的思想,枚举第一个的状态,两种可能,那剩下的就可以唯一确定了,最后检查最后一位即可
#include <iostream> #include <stdio.h> #include <cstring> #include <string> using namespace std; #define INF 0x3f3f3f3f int src, des, r, t; int ans; int getBit(int c, int i) { return 1 & (c >> i); } void setBit(int &c, int i, int v) { if (v) c |= (1 << i); else c &= ~(1 << i); } void flipBit(int &c, int i) { c ^= (1 << i); } int main() { //freopen("1.txt", "r", stdin); string a; cin >> a; int len = a.length(); for (int i = 0; i < len; i++) setBit(src, i, a[i]-'0'); cin >> a; for (int i = 0; i < len; i++) setBit(des, i, a[i]-'0'); int Min, cnt; for (int p = 0; p < 2; p++) { Min = INF; cnt = 0; t = src; if (p) { flipBit(t, 0); flipBit(t, 1); cnt++; } for (int i = 1; i < len; i++) { if (getBit(t, i-1) != getBit(des, i-1)) { cnt++; flipBit(t, i); if (i < len-1) flipBit(t, i+1); } } if (getBit(t, len-1) == getBit(des, len-1)) { if (cnt < Min) { Min = cnt; ans = cnt; } } } if (Min == INF) cout << "impossible"; else cout << ans; return 0; }
poj 1166 拨钟问题
有9个时钟,排成一个3*3的矩阵。
|-------| |-------| |-------|
| | | | | | |
|---O | |---O | | O |
| | | | | |
|-------| |-------| |-------|
A B C
|-------| |-------| |-------|
| | | | | |
| O | | O | | O |
| | | | | | | | |
|-------| |-------| |-------|
D E F
|-------| |-------| |-------|
| | | | | |
| O | | O---| | O |
| | | | | | | |
|-------| |-------| |-------|
G H I
(图 1)
现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。
移动 影响的时钟
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
输入9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。输出输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。样例输入
3 3 0 2 2 2 2 1 2
样例输出
4 5 8 9
每个钟表有4种拨法,且与顺序无关,枚举即可 4^9种可能
#include <iostream> #include <stdio.h> #include <cstring> using namespace std; #define INF 0x3f3f3f3f; int ori[4][4], s[4][4]; int t[10]; bool ok() { for (int i = 1; i <=3; i++) { for (int j = 1; j <=3; j++) { if (s[i][j]) return 0; } } return 1; } int main() { //freopen("1.txt", "r", stdin); for (int i = 1; i <= 3; i++) for (int j = 1; j <= 3; j++) cin >> ori[i][j]; int Min = INF; for (int i1 = 0; i1 < 4; i1++) for (int i2 = 0; i2 < 4; i2++) for (int i3 = 0; i3 < 4; i3++) for (int i4 = 0; i4 < 4; i4++) for (int i5 = 0; i5 < 4; i5++) for (int i6 = 0; i6 < 4; i6++) for (int i7 = 0; i7 < 4; i7++) for (int i8 = 0; i8 < 4; i8++) for (int i9 = 0; i9 < 4; i9++) { memcpy(s, ori, sizeof(ori)); //每种枚举情况都是独立的 s[1][1] = (s[1][1]+i1+i2+i4)%4; //A s[1][2] = (s[1][2]+i1+i2+i3+i5)%4;//B s[1][3] = (s[1][3]+i2+i3+i6)%4;//C s[2][1] = (s[2][1]+i1+i4+i5+i7)%4;//D s[2][2] = (s[2][2]+i1+i3+i5+i7+i9)%4;//E s[2][3] = (s[2][3]+i3+i5+i6+i9)%4;//F s[3][1] = (s[3][1]+i4+i7+i8)%4;//G s[3][2] = (s[3][2]+i5+i7+i8+i9)%4;//H s[3][3] = (s[3][3]+i6+i8+i9)%4;//I if (ok()) { int tot = i1+i2+i3+i4+i5+i6+i7+i8+i9; // cout << tot << endl; if (tot < Min) { Min = tot; t[1] = i1; t[2] = i2; t[3] = i3; t[4] = i4; t[5] = i5; t[6] = i6; t[7] = i7; t[8] = i8; t[9] = i9; } } } for (int i = 1; i <= 9; i++) { if (t[i] && i!=9) { for (int j = 0; j < t[i]; j++) cout << i << " "; } else if (t[i] && i == 9) { for (int j = 0; j < t[i]-1; j++) cout << i << " "; cout << i; } } return 0; }