usaco Party Lamps report
2015-09-04 15:53
337 查看
这道题核心的算法是搜索,然后用状态压缩(位运算)来优化。
有必要好好体会一下位运算具体的实施过程,把一些看起来不太容易用位运算做的问题使用其来提速。
换句话讲,每一个步骤都考虑到其最优的可能对于整体性能的提升是很重要的。
首先1《《a,可以表示一个在第a位置上是1的数,如果现在用一个状态数b,b&a用来检测b的第a位置上是否为1.
|的作用往往体现在添加状态,b|a可以使第a位变成1,无论之前是什么。
还要记住一个^异或运算符,自己造好需要的运算。检测一下它的可行性就好。
标准答案写的比我的精简多了,所以我就不贴自己的了,直接附上标程以供参考:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAXLAMP 6
#define LAMPMASK ((1<<MAXLAMP)-1)
int nlamp;
int nswitch;
int ison;
int known;
int poss[1<<MAXLAMP];
int flip[4] = {
LAMPMASK, /* flip all lights */
LAMPMASK & 0xAA, /* flip odd lights */
LAMPMASK & 0x55, /* flip even lights */
LAMPMASK & ((1<<(MAXLAMP-1))|(1<<(MAXLAMP-4))) /* lights 1, 4 */
};
/*
* Starting with current light state ``lights'', flip exactly n switches
* with number >= i.
*/
void
search(int lights, int i, int n)
{
if(n == 0) {
if((lights & known) == ison)
poss[lights] = 1;
return;
}
for(; i<4; i++)
search(lights ^ flip[i], i+1, n-1);
}
void
printseq(FILE *fout, int lights)
{
int i;
char s[100+1];
for(i=0; i<nlamp; i++)
s[i] = (lights & (1<<(MAXLAMP-1 - i%MAXLAMP))) ? '1' : '0';
s[nlamp] = '\0';
fprintf(fout, "%s\n", s);
}
void
main(void)
{
FILE *fin, *fout;
int a, i, impossible;
fin = fopen("lamps.in", "r");
fout = fopen("lamps.out", "w");
assert(fin != NULL && fout != NULL);
fscanf(fin, "%d %d", &nlamp, &nswitch);
for(;;) {
fscanf(fin, "%d", &a);
if(a == -1)
break;
a = MAXLAMP-1 - (a-1) % MAXLAMP;
ison |= 1<<a;
known |= 1<<a;
}
for(;;) {
fscanf(fin, "%d", &a);
if(a == -1)
break;
a = MAXLAMP-1 - (a-1) % MAXLAMP;
assert((ison & (1<<a)) == 0);
known |= 1<<a;
}
if(nswitch > 4)
if(nswitch%2 == 0)
nswitch = 4;
else
nswitch = 3;
for(; nswitch >= 0; nswitch -= 2)
search(LAMPMASK, 0, nswitch);
impossible = 1;
for(i=0; i<(1<<MAXLAMP); i++) {
if(poss[i]) {
printseq(fout, i);
impossible = 0;
}
}
if(impossible)
fprintf(fout, "IMPOSSIBLE\n");
exit(0);
}
有必要好好体会一下位运算具体的实施过程,把一些看起来不太容易用位运算做的问题使用其来提速。
换句话讲,每一个步骤都考虑到其最优的可能对于整体性能的提升是很重要的。
首先1《《a,可以表示一个在第a位置上是1的数,如果现在用一个状态数b,b&a用来检测b的第a位置上是否为1.
|的作用往往体现在添加状态,b|a可以使第a位变成1,无论之前是什么。
还要记住一个^异或运算符,自己造好需要的运算。检测一下它的可行性就好。
标准答案写的比我的精简多了,所以我就不贴自己的了,直接附上标程以供参考:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAXLAMP 6
#define LAMPMASK ((1<<MAXLAMP)-1)
int nlamp;
int nswitch;
int ison;
int known;
int poss[1<<MAXLAMP];
int flip[4] = {
LAMPMASK, /* flip all lights */
LAMPMASK & 0xAA, /* flip odd lights */
LAMPMASK & 0x55, /* flip even lights */
LAMPMASK & ((1<<(MAXLAMP-1))|(1<<(MAXLAMP-4))) /* lights 1, 4 */
};
/*
* Starting with current light state ``lights'', flip exactly n switches
* with number >= i.
*/
void
search(int lights, int i, int n)
{
if(n == 0) {
if((lights & known) == ison)
poss[lights] = 1;
return;
}
for(; i<4; i++)
search(lights ^ flip[i], i+1, n-1);
}
void
printseq(FILE *fout, int lights)
{
int i;
char s[100+1];
for(i=0; i<nlamp; i++)
s[i] = (lights & (1<<(MAXLAMP-1 - i%MAXLAMP))) ? '1' : '0';
s[nlamp] = '\0';
fprintf(fout, "%s\n", s);
}
void
main(void)
{
FILE *fin, *fout;
int a, i, impossible;
fin = fopen("lamps.in", "r");
fout = fopen("lamps.out", "w");
assert(fin != NULL && fout != NULL);
fscanf(fin, "%d %d", &nlamp, &nswitch);
for(;;) {
fscanf(fin, "%d", &a);
if(a == -1)
break;
a = MAXLAMP-1 - (a-1) % MAXLAMP;
ison |= 1<<a;
known |= 1<<a;
}
for(;;) {
fscanf(fin, "%d", &a);
if(a == -1)
break;
a = MAXLAMP-1 - (a-1) % MAXLAMP;
assert((ison & (1<<a)) == 0);
known |= 1<<a;
}
if(nswitch > 4)
if(nswitch%2 == 0)
nswitch = 4;
else
nswitch = 3;
for(; nswitch >= 0; nswitch -= 2)
search(LAMPMASK, 0, nswitch);
impossible = 1;
for(i=0; i<(1<<MAXLAMP); i++) {
if(poss[i]) {
printseq(fout, i);
impossible = 0;
}
}
if(impossible)
fprintf(fout, "IMPOSSIBLE\n");
exit(0);
}
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例