多边形翻转问题

一个正八边形,每条边有0,1两种状态,每次改变一条边的状态会同时改变与它相邻的边的状态,输入八个数作为八边形的初始状态,问最少多少步可以把所有边都置为0?

测试用例:0 0 0 0 0 0 0 1 ;

输出 :5 

这道题的关键在于,翻转的顺序是不重要的。给八条边编号0-7;1234的翻转结果和4321的结果是一样的。

故,如果一条边在一个翻转序列中出现两次,那么就可以消掉这两次。

如:12341234这个翻转序列相当于没有动!

理解了上面,我们就可以开始构建自己的最短翻转序列了。使用穷举法,从翻转一条边开始,直到八条边都被翻转过结束。

翻转序列的增加代码如下:

void Plus(vector<int>& NeedPlus)
{
    //先判断要不要加一条翻转的边,当前数组全都是最大值时,说明已经穷举完NeedPlus.size()下的所有可能,增大size.
    bool IsAllMax = true;
    for (auto i : NeedPlus)
    {
        if (i != SIDE_NUM - 1)
            IsAllMax = false;
    }
    if (IsAllMax)
    {
        NeedPlus.emplace_back(0);
        for (int i = 0; i < NeedPlus.size(); ++i)
        {
            NeedPlus[i] = 0;
        }
    }
    else
    {
        for (int i = NeedPlus.size() - 1; i > -1; --i)
        {
            if (NeedPlus[i] < SIDE_NUM - 1)
            {
                ++NeedPlus[i];
                //每次自增完毕要将后面的字符置0
                for (int j = i + 1; j < NeedPlus.size(); ++j)
                {
                    NeedPlus[j] = 0;
                }
                break;
            }
        }
    }
    return;
}

翻转某些边的代码如下,有两个重载,第二个参数输入是边,就翻转单个的边,输入的是数组,就翻转数组中的所有边。

void Reverse(vector<int>& sides, int i)
{
    if (i > SIDE_NUM - 1)
    {
        return;
    }
    int pre = i - 1;
    int back = (i + 1) % SIDE_NUM;
    if (pre < 0)
    {
        pre = SIDE_NUM-1;
    }
    sides[pre] = 1 - sides[pre];
    sides[i] = 1 - sides[i];
    sides[back] = 1 - sides[back];
}

void Reverse(vector<int>& sides, vector<int>& WaitForChange)
{
    for (auto i : WaitForChange)
    {
        Reverse(sides, i);
    }
}

下面是判断是否全0的代码

bool IsAllZero(vector<int>& sides)
{
    for (auto i : sides)
    {
        if (i != 0)
            return false;
    }
    return true;
}

最后是主函数,acm模式,先接收一个数字代表有多少组输入数据,用一个数组存储八边形中每条边的状态。

int main()
{
    int n;
    vector<int> sides(SIDE_NUM,0);
    cin >> n;
    for (; n > 0; --n)
    {
        //获取每条边状态
        for (int i = 0; i < sides.size(); ++i)
        {
            cin >> sides[i];
        }
        //tmp为了方便每次计算反转序列后恢复初始状态
        vector<int> tmp = sides;
        //NeedToChange里面存储翻转序列
        vector<int> NeedToChange;
        while (!IsAllZero(tmp))
        {
            tmp = sides;
            Plus(NeedToChange);
            Reverse(tmp, NeedToChange);
        }
        //最后翻转序列的长度就是最少的步数
        cout << NeedToChange.size() << endl;
    }
}

完整代码放到下面了,改SIDE_NUM可以适用到任意边型。

#include <iostream>
#include <vector>
using namespace std;
#define SIDE_NUM 8

void Reverse(vector<int>& sides, int i)
{
    if (i > SIDE_NUM - 1)
    {
        return;
    }
    int pre = i - 1;
    int back = (i + 1) % SIDE_NUM;
    if (pre < 0)
    {
        pre = SIDE_NUM-1;
    }
    sides[pre] = 1 - sides[pre];
    sides[i] = 1 - sides[i];
    sides[back] = 1 - sides[back];
}

void Reverse(vector<int>& sides, vector<int>& WaitForChange)
{
    for (auto i : WaitForChange)
    {
        Reverse(sides, i);
    }
}

bool IsAllZero(vector<int>& sides)
{
    for (auto i : sides)
    {
        if (i != 0)
            return false;
    }
    return true;
}

void Plus(vector<int>& NeedPlus)
{
    bool IsAllMax = true;
    for (auto i : NeedPlus)
    {
        if (i != SIDE_NUM - 1)
            IsAllMax = false;
    }
    if (IsAllMax)
    {
        NeedPlus.emplace_back(0);
        for (int i = 0; i < NeedPlus.size(); ++i)
        {
            NeedPlus[i] = 0;
        }
    }
    else
    {
        for (int i = NeedPlus.size() - 1; i > -1; --i)
        {
            if (NeedPlus[i] < SIDE_NUM - 1)
            {
                ++NeedPlus[i];
                for (int j = i + 1; j < NeedPlus.size(); ++j)
                {
                    NeedPlus[j] = 0;
                }
                break;
            }
        }
    }
    return;
}

int main()
{
    int n;
    vector<int> sides(SIDE_NUM,0);
    cin >> n;
    for (; n > 0; --n)
    {
        for (int i = 0; i < sides.size(); ++i)
        {
            cin >> sides[i];
        }
        vector<int> tmp = sides;
        vector<int> NeedToChange;
        while (!IsAllZero(tmp))
        {
            tmp = sides;
            Plus(NeedToChange);
            Reverse(tmp, NeedToChange);
        }
        cout << NeedToChange.size() << endl;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值