USACO:2.2.4 Party Lamps 派对灯

USACO:2.2.4  Party Lamps 派对灯


一、题目描述

★Party Lamps 派对灯

在IOI98 的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1 到N 被标上号码.

这些灯都连接到四个按钮:
按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄灭,本来是关着的灯被点亮.
按钮2:当按下此按钮,将改变所有奇数号的灯.
按钮3:当按下此按钮,将改变所有偶数号的灯.
按钮4:当按下此按钮,将改变所有序号是3*K+1(K>=0)的灯.例如:1,4,7...
一个计数器C 记录按钮被按下的次数.
当宴会开始,所有的灯都亮着,此时计数器C 为0.
你将得到计数器C(0<=C<=10000)上的数值和经过若干操作后某些灯的状态. 写一个程序去找出所有的灯最后可能的与所给出信息相符的状态,并且没有重复.
PROGRAM NAME: lamps
INPUT FORMAT

不会有灯会在输入中出现两次.
第一行: N.
第二行: C 最后显示的数值.
第三行: 最后亮着的灯,用一个空格分开,以-1 为结束.
第四行: 最后关着的灯,用一个空格分开,以-1 为结束.
SAMPLE INPUT (file lamps.in)
10
1
-1
7 -1
在这个样例中,有10 盏灯,只有1 个按钮被按下.最后7 号灯是关着的.
OUTPUT FORMAT
每一行是所有灯可能的最后状态(没有重复).每一行有N 个字符,第1 个字符表示1 号灯,最后一个
字符表示N 号灯.0 表示关闭,1 表示亮着.这些行必须从小到大排列(看作是二进制数).
如果没有可能的状态,则输出一行'IMPOSSIBLE'.
SAMPLE OUTPUT (file lamps.out)
0000000000
0101010101
0110110110

在这个样例中,有三种可能的状态:

所有灯都关着

1,4,7,10 号灯关着,2,3,5,6,8,9 亮着.

1,3,5,7,9 号灯关着,2, 4, 6, 8, 10 亮着.

二、题目解答

   每个开关按钮按2次和没按效果是一样的。所以每个按钮或者按或者不按,一共有2^4=16中开关状态。枚举每个按钮是否按下,然后生成结果,看是否满足条件,排序输出即可(注意判重)。

   另外,根据四种开关的操作效果,灯状态的周期为6,因此当N>=6时只需处理前6个灯, 排序时转换为10进制数, 输出时反复输出二进制的前6个的状态.


源代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include using namespace std;int N,C;
vector final_on,final_off;
string s1;
map mymap;//第一个为key,int类型,必须唯一。
int state6[16];//利用N个灯的周期性,只要考虑前6个灯即可;最多16种状态int check(string s){for(int i=0;i>N;fin>>C;for(int i=0;fin>>i&&i!=-1;i++)final_on.push_back(i);for(int i=0;fin>>i&&i!=-1;i++)final_off.push_back(i);//从开关的状态对应前6个灯的状态,最高位为第一个开关//关于状态的记录,用一个int存储N个灯的前6位的状态就行了。
//状态的改变,通过开关,4种操作也很简单,用异或就可以搞定:
//操作1:异或(111111)=63 二进制数 等价于取反
//操作2:异或(010101)=21 改变偶数位
//操作3:异或(101010)=42 改变奇数位
//操作4:异或(100100)=36 改变1、4、7位int j=0;int c=C%2;int newstate;if(c==0){newstate=~0;if(mymap[newstate]==0)  {state6[j++]=newstate;mymap[newstate]=1;}//操作1if(C>1){//****0011 0101 0110 1001 1010 1100 状态3,5,6,9,10,12;//只有两个开关为打开状态,C可能为2+2的幂次//0011newstate=~42^36;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////0101newstate=~36^21;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////0110newstate=~42^21;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1001newstate=~36^63;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1010newstate=~42^63;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1100newstate=~21^63;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////****1111 状态15;C可能为4+2的幂次if(C>=4){newstate=~21^63^36^42;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}//}}}else {//C为奇数//****0001 0010 0100 1000 状态1,2,4,8;//只有一个开关为打开状态,C可能为1+2的幂次,奇数//0001newstate=~36;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////0010newstate=~42;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////0100newstate=~21;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1000newstate=~63;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////****0111 1101 1011 1110 状态7,13,11,14;可能为3+2的幂次if(C>2){//0111newstate=~21^42^36;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1101newstate=~63^21^36;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1011newstate=~63^42^36;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}////1110newstate=~63^42^21;if(mymap[newstate]==0) { state6[j++]=newstate; mymap[newstate]=1;}//}}//16种开关状态 (对应4种开关的状态)//0000 状态0;C可能为0+2的幂次(等效按开关0次)
//1111 状态15;C可能为4+2的幂次(等效按开关4次)
//0011 0101 0110 1001 1010 1100 状态3,5,6,9,10,12;C可能为2+2的幂次(等效按开关2次)
//0001 0010 0100 1000 状态1,2,4,8;C可能为1+2的幂次,奇数(等效按开关1次)
//0111 1101 1011 1110 状态7,13,11,14;可能为3+2的幂次(等效按开关3次)sort(state6,state6+j);//int flag=0;for( int i=0;i-1;j--){if((decimal>>j)&1) ss="1";//整数化为二进制的字符串else	ss="0";s=s+ss;}if(check(s)){for(int i=0;i

官方答案

//There are a number of insights required for this problem.
//The main insight is that no matter which switches get pressed, the light pattern will repeat every six lamps.
//Another insight is that the order of switch presses does not matter,
//and that pressing a switch twice is the same as not pressing a switch at all.
//Any even number of switch presses greater than four might as well just be four switch presses,
//and any odd number greater than three might as well just be three presses.
//We can treat the light information as describing only the first six lamps (by treating lamp n as lamp (n mod 6)),
//and only try pressing each switch once or not at all.
//To maintain the actual information about which lights are on, we use an integer holding six bits.
//The least significant bit is light 6, the next least is light 5, and so on.
//This has the effect that treating these bit strings as normal numbers sorts the same way that we need to print them.
//Switches are represented as bit vectors that say which lights get toggled.#include 
#include 
#include 
#include #define MAXLAMP	6  //定义最大灯数 6,因为灯的状态具有循环特性。
#define LAMPMASK	((1<= 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 4){if(nswitch%2 == 0)nswitch = 4;//偶数情况,4/2/0elsenswitch = 3;//奇数情况,3/1}for(; nswitch >= 0; nswitch -= 2)//搜索对应情况search(LAMPMASK, 0, nswitch);//LAMPMASK灯的原始状态,0代表第一种开关操作,nswitch代表最多几次开关操作impossible = 1;for(i=0; i<(1<




由于自身是初学者,编程能力有限,未达到专业程序员的水平,可能误导大家,请大家甄读;文字编辑也一般,文中可能会有措辞不当。博文中的错误和不足敬请读者批评指正。

部分引自  http://pingce.ayyz.cn:9000/usaco/20110129214306/lamps_001.html





本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章