[poj]开关类问题 枚举 位运算

时间:2024-08-06 20:35:02

poj 1222  EXTENDED LIGHTS OUT

开关只有两种方案 按和不按,按两次相当于关

只用枚举第一排开关的按法即可,剩下的行为使上一排的灯全部关闭,按法可以确定,并且是唯一的。

最后检查最后一行是否都为0,都为0为可行的方案。  用位运算来实现。

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std; char ol[], l[], r[];
int t; int getBit(char c, int i)
{
return & (c>>i);
} void setBit(char &c, int i, int v)
{
if (v) {
c |= ( << i);
}
else
c &= ~( << i);
} void FlipBit(char &c, int i)
{
c ^= ( << i);
} void output()
{
cout << "PUZZLE #" << t << endl;
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
cout << getBit(r[i], j);
if (j < )
cout << " ";
}
cout << endl;
}
} int main()
{
//freopen("1.txt", "r", stdin);
int T;
cin >> T;
for (t = ; t <= T; t++) {
for (int i = ; i < ; i++)
for (int j = ; j < ; j++) {
int s;
cin >> s;
setBit(ol[i], j, s);
} for (int n = ; n < ; n++) { //枚举第一列方案0~2^6-1
memcpy(l, ol, sizeof(ol));
int switchs = n; //当前行的开关状态
for (int i = ; i < ; i++) {
r[i] = switchs;
for (int j = ; j < ; j++) {
if (getBit(switchs, j)) {
if (j > )
FlipBit(l[i], j-);
FlipBit(l[i], j);
if (j < )
FlipBit(l[i], j+);
}
}
if (i < )
l[i+] ^=switchs;
switchs = l[i]; //i+1行灯的状态由第i行灯的状态决定
}
if (l[] == ) {
output();
break;
}
}
} return ;
}

特殊密码锁

描述

有一种特殊的二进制密码锁,由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 & (c >> i);
} void setBit(int &c, int i, int v)
{
if (v)
c |= ( << i);
else
c &= ~( << i);
} void flipBit(int &c, int i)
{
c ^= ( << i);
} int main()
{
//freopen("1.txt", "r", stdin);
string a;
cin >> a;
int len = a.length();
for (int i = ; i < len; i++)
setBit(src, i, a[i]-''); cin >> a;
for (int i = ; i < len; i++)
setBit(des, i, a[i]-''); int Min, cnt;
for (int p = ; p < ; p++) {
Min = INF; cnt = ;
t = src;
if (p) {
flipBit(t, );
flipBit(t, );
cnt++;
}
for (int i = ; i < len; i++) {
if (getBit(t, i-) != getBit(des, i-)) {
cnt++;
flipBit(t, i);
if (i < len-)
flipBit(t, i+);
}
}
if (getBit(t, len-) == getBit(des, len-)) {
if (cnt < Min) {
Min = cnt;
ans = cnt;
}
}
}
if (Min == INF)
cout << "impossible";
else
cout << ans; return ;
}

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[][], s[][];
int t[]; bool ok()
{
for (int i = ; i <=; i++) {
for (int j = ; j <=; j++) {
if (s[i][j])
return ;
}
}
return ;
}
int main()
{
//freopen("1.txt", "r", stdin);
for (int i = ; i <= ; i++)
for (int j = ; j <= ; j++)
cin >> ori[i][j]; int Min = INF;
for (int i1 = ; i1 < ; i1++)
for (int i2 = ; i2 < ; i2++)
for (int i3 = ; i3 < ; i3++)
for (int i4 = ; i4 < ; i4++)
for (int i5 = ; i5 < ; i5++)
for (int i6 = ; i6 < ; i6++)
for (int i7 = ; i7 < ; i7++)
for (int i8 = ; i8 < ; i8++)
for (int i9 = ; i9 < ; i9++) {
memcpy(s, ori, sizeof(ori)); //每种枚举情况都是独立的
s[][] = (s[][]+i1+i2+i4)%; //A
s[][] = (s[][]+i1+i2+i3+i5)%;//B
s[][] = (s[][]+i2+i3+i6)%;//C
s[][] = (s[][]+i1+i4+i5+i7)%;//D
s[][] = (s[][]+i1+i3+i5+i7+i9)%;//E
s[][] = (s[][]+i3+i5+i6+i9)%;//F
s[][] = (s[][]+i4+i7+i8)%;//G
s[][] = (s[][]+i5+i7+i8+i9)%;//H
s[][] = (s[][]+i6+i8+i9)%;//I
if (ok()) {
int tot = i1+i2+i3+i4+i5+i6+i7+i8+i9;
// cout << tot << endl;
if (tot < Min) {
Min = tot;
t[] = i1; t[] = i2; t[] = i3;
t[] = i4; t[] = i5; t[] = i6;
t[] = i7; t[] = i8; t[] = i9;
}
} }
for (int i = ; i <= ; i++) {
if (t[i] && i!=) {
for (int j = ; j < t[i]; j++)
cout << i << " ";
}
else if (t[i] && i == ) {
for (int j = ; j < t[i]-; j++)
cout << i << " ";
cout << i;
}
} return ;
}

相关文章