POJ1176 (规律循环)

问题:

  有N个开着的灯,和控制这个N个灯的四个开关。四个开关作用不同。第一个开关:flip所有的灯。第二个开关:flip奇数编号的灯。第三个开关:flip偶数编号的灯。第四个开关:flip编号为3 * K + 1 的灯,其中K = 0,1,2....。已知在C次操作后其中几个灯的状态,给出所有灯在这C次操作后所有可能的状态。

方法:

  通过观察可以发现,这些灯一共可以分成4种,同种灯无论在何种操作下,状态都是相同的。即:(1)编号为1,7,13,19....的灯。(2)编号为4,10,16,22....的灯。(3)编号为奇数,但是不属于(1)的灯。 (4)编号为偶数,但是不属于(2)的灯。

    对于第(1)种灯,唯1,2,4号开关能够控制,且这些开关的作用是等效的。

    对于第(2)种灯,唯有1,3号开关能够控制,且这些开关的作用是等效的。

    对于第(3)种灯,唯有1,2号开关能够控制,且这些开关的作用是等效的。

    对于第(4)种灯,唯有第1,3,4号开关能够控制,且这些开关的作用是等效的。

  同一个开关无论按动多少次,其效果只有两种。即所有奇数次的按动的效果与按动一次相同;所有偶数次的按动与不按动的效果也相同。

  现在只需将这四个开关的按动次数按奇偶枚举(共有2 * 2 * 2 * 2 = 16种情况),然后与已知的C次操作后的灯的状态对比即可,若符合,则为潜在的正确答案。这里说是“潜在”的答案,是因为还需要考虑该开关组合能否在C次操作内完成。不可能的情况共有2种:(1)按动奇数次的开关的个数大于C。(2)按动奇数次的开关的个数与C的奇偶性不同。排除这两种情况之后,便得到了正确答案。

 

附代码:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

bool isEven(int x){
    return (x % 2 == 0);
}
bool is3K1(int x){
    return ((x - 1) % 3 == 0);
}

int main(){
    int N, C;
    int isOn[4] = {0};
    cin >> N >> C;
    vector<string> result;int temp;
    while(1){
        cin >> temp;
        if(temp == -1)
            break;
        if(is3K1(temp) && isEven(temp)){
            isOn[3] = 1;    
        }else if(is3K1(temp) && ! isEven(temp)){
            isOn[0] = 1;
        }else if(isEven(temp)){
            isOn[1] = 1;    
        }else{
            isOn[2] = 1;    
        }
    }
    while(1){
        cin >> temp;
        if(temp == -1)
            break;
        if(is3K1(temp) && isEven(temp)){
            isOn[3] = -1;    
        }else if(is3K1(temp) && ! isEven(temp)){
            isOn[0] = -1;
        }else if(isEven(temp)){
            isOn[1] = -1;    
        }else{
            isOn[2] = -1;    
        }
    }

    for(int i = 0; i < 16; i++){
        string temp(N, '1');
        bool on[4] = {0};
        if((i & 1) == 0)
            on[0] = 0;
        else
            on[0] = 1;
        if((i & 2) == 0)
            on[1] = 0;
        else
            on[1] = 1;
        if((i & 4) == 0)
            on[2] = 0;
        else
            on[2] = 1;
        if((i & 8) == 0)
            on[3] = 0;
        else
            on[3] = 1;

        if((on[0] + on[1] + on[3]) % 2 == 0){
            if(isOn[0] == -1)
                continue;
        }else{
            if(isOn[0] == 1)
                continue;
        }
        if((on[0] + on[2]) % 2 == 0){
            if(isOn[1] == -1)
                continue;
        }else{
            if(isOn[1] == 1)
                continue;
        }
        if((on[0] + on[1] ) % 2 == 0){
            if(isOn[2] == -1)
                continue;
        }else{
            if(isOn[2] == 1)
                continue;
        }
        if((on[0] + on[2] + on[3]) % 2 == 0){
            if(isOn[3] == -1)
                continue;
        }else{
            if(isOn[3] == 1)
                continue;
        }
        if((on[0] + on[1] + on[2] + on[3]) % 2 != C % 2)
            continue;
        if((on[0] + on[1] + on[2] + on[3]) > C)
            continue;
        if(on[0] == 1){
            for(int i = 0; i < temp.size(); i++)
                if(temp[i] == '0')
                    temp[i] = '1';
                else
                    temp[i] = '0';
        }
        if(on[1] == 1){
            for(int i = 0; i < temp.size(); i += 2){
                if(temp[i] == '0')
                    temp[i] = '1';
                else
                    temp[i] = '0';
            }
        }
        if(on[2] == 1){
            for(int i = 1; i < temp.size(); i += 2){
                if(temp[i] == '0')
                    temp[i] = '1';
                else
                    temp[i] = '0';
            }
        }
        if(on[3] == 1){
            for(int i = 0; i < temp.size(); i += 3)
                if(temp[i] == '0')
                    temp[i] = '1';
                else
                    temp[i] = '0';
        }
        result.push_back(temp);
    }
    sort(result.begin(), result.end());
    for(int i = 0; i < result.size(); i++)
        cout << result[i] << endl;;
}

转载于:https://www.cnblogs.com/dogspeek/archive/2012/06/26/2563834.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值