Party Lamps
IOI 98
To brighten up the gala dinner of the IOI'98 we have a set of N (10 <= N <= 100) colored lamps numbered from 1 to N.
The lamps are connected to four buttons:
- Button 1: When this button is pressed, all the lamps change their state: those that are ON are turned OFF and those that are OFF are turned ON.
- Button 2: Changes the state of all the odd numbered lamps.
- Button 3: Changes the state of all the even numbered lamps.
- Button 4: Changes the state of the lamps whose number is of the form 3xK+1 (with K>=0), i.e., 1,4,7,...
A counter C records the total number of button presses.
When the party starts, all the lamps are ON and the counter C is set to zero.
You are given the value of counter C (0 <= C <= 10000) and the final state of some of the lamps after some operations have been executed. Write a program to determine all the possible final configurations of the N lamps that are consistent with the given information, without repetitions.
PROGRAM NAME: lamps
INPUT FORMAT
No lamp will be listed twice in the input.
Line 1: | N |
Line 2: | Final value of C |
Line 3: | Some lamp numbers ON in the final configuration, separated by one space and terminated by the integer -1. |
Line 4: | Some lamp numbers OFF in the final configuration, separated by one space and terminated by the integer -1. |
SAMPLE INPUT (file lamps.in)
10 1 -1 7 -1
In this case, there are 10 lamps and only one button has been pressed. Lamp 7 is OFF in the final configuration.
OUTPUT FORMAT
Lines with all the possible final configurations (without repetitions) of all the lamps. Each line has N characters, where the first character represents the state of lamp 1 and the last character represents the state of lamp N. A 0 (zero) stands for a lamp that is OFF, and a 1 (one) stands for a lamp that is ON. The lines must be ordered from least to largest (as binary numbers).
If there are no possible configurations, output a single line with the single word `IMPOSSIBLE'
SAMPLE OUTPUT (file lamps.out)
0000000000 0101010101 0110110110
In this case, there are three possible final configurations:
- All lamps are OFF
- Lamps 1, 4, 7, 10 are OFF and lamps 2, 3, 5, 6, 8, 9 are ON.
- Lamps 1, 3, 5, 7, 9 are OFF and lamps 2, 4, 6, 8, 10 are ON.
解题思路:灯的开关有四种方式,每种方式只能使用一次,因为使用两次和不使用是一样的。因此总的使用情况有2^4种,依次枚举找出符合条件的,再按从大到小排序输出即可。我是用个类存bool行表状态。因为情况最多只有16种,因此取bool型的前四位转化为十进制来排序,最后输出即可。
另外还有一点就是开关使用次数。只要前面枚举时看使用的开关数小于等于题目要求数并且使用开关数于题目要求数同奇偶即可。(因为使用两次一样的开关和不使用一样)
/*
ID:nealgav1
PROG:lamps
LANG:C++
*/
#include<fstream>
#include<algorithm>
#include<cstring>
using namespace std;
const int mm=230;//灯的数量
class node
{public:
int num;//用来排序的,取vis[]前四位转化为十进制
bool vis[mm];
node()
{ num=0;
memset(vis,1,sizeof(vis));//初始状态为全开
}
}f[21];
node _ans[21];//存最后的结果
//bool vis[21][mm];
int on[mm],off[mm],ans[mm],lans,lon,loff;//最后状态的开关要求
int _num;
int n,c;
void button(int num,int x)//四种开关操作
{
if(x==1)
{
for(int i=0;i<n;i++)
f[num].vis[i]^=1;
}
else if(x==2)
{
for(int i=0;i<n;i+=2)
f[num].vis[i]=f[num].vis[i]^1;
}
else if(x==3)
{
for(int i=1;i<n;i+=2)
f[num].vis[i]=f[num].vis[i]^1;
}
else
{ for(int i=0;i<n;i+=3)
f[num].vis[i]=f[num].vis[i]^1;
}
}
int lowbit(int x)
{
return x&(-x);
}
bool look_up(int num,int x)//判断状态可行性
{
int nu=1,km=0;
while(x)
{
if(x&1)
{
button(num,nu);km++;
}
x>>=1;nu++;
}
if(km>c||(km&1)!=(c&1))//若使用开关数大于要求或使用开关数与要求奇偶性不同
return 0; //则不符合条件
for(int i=0;i<lon-1;i++)
if(!f[num].vis[on[i]-1])
return 0;
for(int i=0;i<loff-1;i++)
if(f[num].vis[off[i]-1])
return 0;
return 1;
}
void charge()
{
lans=0;
for(int i=0;i<16;i++)//枚举16种状态
{
if(look_up(i,i))
{
ans[lans++]=i;
}
}
}
bool cmp(node a,node b)
{
return a.num<b.num;
}
void b_sort()//排序
{ _num=0;
for(int i=0;i<lans;i++,_num++)
{
_ans[_num]=f[ans[i]];
for(int j=0;j<8;j++)
{ _ans[_num].num<<=1;
if(_ans[_num].vis[j])
_ans[_num].num+=1;
}
}
//cout<<"lans "<<lans<<"lans\n";
sort(_ans,_ans+_num,cmp);
}
int main()
{
ifstream cin("lamps.in");
ofstream cout("lamps.out");
cin>>n>>c;
for(lon=0;on[lon-1]!=-1;lon++)
{
cin>>on[lon];
}
for(loff=0;off[loff-1]!=-1;loff++)
{
cin>>off[loff];
}
charge();
b_sort();
if(_num<=0)cout<<"IMPOSSIBLE\n";
else
for(int i=0;i<_num;i++)
{for(int j=0;j<n;j++)
cout<<_ans[i].vis[j];
//cout<<_ans[i].num<<"\n";
cout<<"\n";
}
}
USER: Neal Gavin Gavin [nealgav1] TASK: lamps LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.011 secs, 3356 KB] Test 2: TEST OK [0.000 secs, 3356 KB] Test 3: TEST OK [0.000 secs, 3356 KB] Test 4: TEST OK [0.000 secs, 3356 KB] Test 5: TEST OK [0.000 secs, 3356 KB] Test 6: TEST OK [0.000 secs, 3356 KB] Test 7: TEST OK [0.000 secs, 3356 KB] Test 8: TEST OK [0.011 secs, 3356 KB] All tests OK.
Your program ('lamps') produced all correct answers! This is your submission #2 for this problem. Congratulations!
Here are the test data inputs:
------- test 1 ----
10
0
-1
-1
------- test 2 ----
10
0
-1
1 -1
------- test 3 ----
20
3
-1
1 3 5 -1
------- test 4 ----
50
100
1 -1
-1
------- test 5 ----
75
250
-1
-1
------- test 6 ----
100
8394
1 7 13 19 25 31 37 43 49 55 -1
64 -1
------- test 7 ----
100
2000
31 86 23 -1
42 -1
------- test 8 ----
100
8950
-1
-1
Keep up the good work!
Thanks for your submission!
Party LampsRuss Cox
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 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 <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);
}