搜索练习1:派对灯

题目描述

在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)上的数值和经过若干操作后某些灯的状态。写一个程序去找出所有灯最后可能的与所给出信息相符的状态,并且没有重复。

输入输出格式

输入格式:
不会有灯会在输入中出现两次。
第一行: N。
第二行: C最后显示的数值。
第三行: 最后亮着的灯,用一个空格分开,以-1为结束。
第四行: 最后关着的灯,用一个空格分开,以-1为结束。

输出格式:
每一行是所有灯可能的最后状态(没有重复)。每一行有N个字符,第1个字符表示1号灯,最后一个字符表示N号灯。0表示关闭,1表示亮着。这些行必须从小到大排列(看作是二进制数)。
如果没有可能的状态,则输出一行’IMPOSSIBLE’。
做题思路
我开始真的太天真了,以为这个是一个纯粹的搜索,(肯定是我水题做多了,皮了),结果一看数据范围0<=C<=10000。。
这里写图片描述
这题模拟怎么搞得出???,于是,在不知道怎么办后,我诚心地去看了大佬的解释,知道了一个按钮按了2次后等于没按(第一位发现的大佬绝对是个天才!!!
然鹅。。。。还是搞不出。。。。
AC思路
我们已经提到,每个按钮按两次都会回归原点,这就意味着其实对于每个按钮,我们只有按与不按两种选择,所以我们只需要枚举各按钮状态,然后判断是否满足条件,既可以得到答案;
代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,lk;
int k[10000];
int a[100][400];
int t=0;
int chu()
{   //1为按,0为不按; 
    for(int i=0;i<=1;i++)//按钮1 
        for(int j=0;j<=1;j++)//按钮2 
            for(int kk=0;kk<=1;kk++)//按钮3 
                for(int z=0;z<=1;z++)//按钮4 
                if((i+j+kk+z)%2==m%2&&i+j+kk+z<=m)//既要满足次数相同,也要满足不超时; 
                {   
                    t++;
                    for(int u=1;u<=n;u++)
                        a[t][u]=1;//初始化; 
                    if(i)
                    for(int u=1;u<=n;u++)
                        a[t][u]=1-a[t][u];
                    if(j)
                    for(int u=1;u<=n;u+=2)
                        a[t][u]=1-a[t][u];
                    if(kk)
                    for(int u=2;u<=n;u+=2)
                        a[t][u]=1-a[t][u];
                    if(z)
                    for(int u=1;u<=n;u+=3)
                        a[t][u]=1-a[t][u];
                    for(int u=1;u<=n;u++)
                    if((a[t][u]==k[u])||(a[t][u]==k[u])||k[u]==-1);//剔除不满足条件的; 
                    else
                    {
                        t--;
                        break;
                    }
                }


    if(!t)cout<<"IMPOSSIBLE"<<endl;//没有就输出impossible; 
     for(int ll=1;ll<=n;ll++)
         for(int i=1;i<=t-1;i++)
             for(int j=1;j<=t-i;j++)
                 for(int k=1;k<=n;k++)
                     if(a[j][k]==a[j+1][k])
                        continue;
                     else if(a[j][k]<a[j+1][k])break;
                     else
                     {
                          swap(a[j],a[j+1]);
                          break;
                     }//按照二进制排序; 
    for(int i=1;i<=t;i++,cout<<endl)
    for(int j=1;j<=n;j++)
            printf("%d",a[i][j]);//输出; 
    return 0;
}
int main()
{
    int ah,b;
    cin>>n;
    cin>>m;
for(int i=1;i<=n;i++)k[i]=-1;
    while(ah!=-1)
    {
        cin>>ah;
        if(ah==-1)break;    
        k[ah]=1;
    }
    while(1)
    {   
        cin>>b;
        if(b==-1)break;
        k[b]=0;//条件数组; 
    }
    chu();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值