题解 POJ 2985 The Pilots Brothers' refrigerator
暴力出奇迹
考虑将每个位置拨 \(/\) 不拨表示为 \(1\) \(/\) \(0\),那么 \(n^2\) 个位置的情况就可以用一个 \(n^2=16\) 位无符号二进制数表示。
考虑对于一种拨开关的方案,可以用 \(\Theta(n^3)(n=4)\) 的时间检验是否可行(\(\Theta(n^2)\) 枚举每一个位置, \(\Theta(n)\) 进行状态翻转操作)
考虑枚举所有拨的方案,并对于每一种方案进行检查是否可行,总时间复杂度 \(\Theta(2^{n^2}n^3)\),由于 \(n\) 很小,可以通过本题。
考虑题目要求的是最优化方案,所以还不能简单地把拨的方案从 \(0\) 到 \(2^{16}-1\) 枚举。
考虑先检验的方案,其二进制下的 \(\operatorname{popcount}\) 值应当尽量的小(\(\operatorname{popcount}\) 表示一个数二进制下各位上 \(1\) 的个数)
考虑对于一个表示检验顺序的数组 way(0..65535)
,我们在将其初始化 for (int i = 0; i < 65536; i++) way[i] = i;
后应当对其按照 \(\operatorname{popcount}\) 值排序。
考虑编写自定义 \(\operatorname{sort}\) 比较函数 PopcountComp
为:
1 bool PopcountComp(int a, int b) {
2 return popcount(a) < popcount(b);
3 }
如果使用 \(STL\) 中的 __builtin_popcount
函数,真实比赛会 \(CE\),因此考虑手打 popcount
1 int Stable[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
2 int popcountS(int a) { return Stable[a >> 4] + Stable[a & 15]; }
3 int popcount(int a) { return popcountS(a >> 8) + popcountS(a & 255); }
此程序第一行为一个手打的 0~15
的 popcount 表,popcountS
通过使用 Stable
中的数据处理 0~255
的数的 popcount 值,popcount
则通过调用 popcountS
处理 0~65535
的数的 popcount 值。
值得一提的是,\(STL\) 中的 popcount 是类似的写法,不过用于查询的表的大小是 \(256\),从而使时间减少了一倍。
总时间复杂度为 \(\Theta(2^{n^2}n^3 + 2^{n^2}log_2{(2^{n^2})}) = \Theta(2^{n^2}n^3 + 2^{n^2}n^2) = \Theta(2^{n^2}n^3)\)
代码
已略去头文件 & I/O优化
// 自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只
// 要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也
// 能够保持自己的本色走下去。 ——陈立杰
/*************************************
* @problem: 2965: The Pilots Brothers' refrigerator.
* @user_name: HKXA0933.
* @time: 2020-06-02.
* @language: C++.
* @upload_place: POJ.
*************************************/
char t[5];
bool status[4][4], tmp[4][4];
int way[65536];
int Stable[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
int popcountS(int a) { return Stable[a >> 4] + Stable[a & 15]; }
int popcount(int a) { return popcountS(a >> 8) + popcountS(a & 255); }
bool PopcountComp(int a, int b) { return popcount(a) < popcount(b); }
bool check(int way) {
memcpy(tmp, status, sizeof(status));
for (int i = 0; i < 16; i++)
if (way & (1 << i)) {
int x = i >> 2, y = i & 3;
tmp[x][0] ^= 1; tmp[x][1] ^= 1; tmp[x][2] ^= 1; tmp[x][3] ^= 1;
tmp[0][y] ^= 1; tmp[1][y] ^= 1; tmp[2][y] ^= 1; tmp[3][y] ^= 1;
tmp[x][y] ^= 1;
}
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
if (!tmp[i][j]) return false;
return true;
}
signed main() {
for (int i = 0; i < 4; i++) {
scanf("%s", t);
for (int j = 0; j < 4; j++)
status[i][j] = t[j] == '-';
}
for (int i = 0; i < 65536; i++) way[i] = i;
sort(way, way + 65536, PopcountComp);
for (int i = 0; i < 65536; i++)
if (check(way[i])) {
printf("%d\n", popcount(way[i]));
for (int j = 0; j < 16; j++)
if (way[i] & (1 << j))
printf("%d %d\n", (j >> 2) + 1, (j & 3) + 1);
break;
}
return 0;
}
// Create File Date : 2020-06-02