牛客——01反转

1. 01反转

题目

牛牛正在挑战一款名为01翻转的游戏。游戏初始有A个0,B个1,牛牛的目标就是把所有的值都变为1,每次操作牛牛可以任意选择恰好K个数字,并将这K个数字的值进行翻转(0变为1,1变为0)。牛牛如果使用最少的操作次数完成这个游戏就可以获得奖品,牛牛想知道最少的操作次数是多少?

例如:A = 4 B = 0 K = 30000 -> 1110 -> 1001 -> 0100 -> 1111

需要的最少操作次数为4

思路

使用广度优先搜索,倒着向后遍历,从最终状态到起始状态。
因为每条路径上边的全都都可以看作为1,所以如果之前遍历了,那么之前的一定比后面的路径(步数)少,所以之前遍历了,后面再遇到就跳过。

#include <iostream>
#include <deque>
#include <vector>

using namespace std;
struct Node
{
    Node(int a, int step, int f)
        : a(a), step(step), f(f)
    {
    }
    int a;    //当前1的个数
    int step; //距离权为1的步数
    int f;    //上次1的个数
};

//a:1的个数,b:0的个数,k每次反转的次数。
int turn0to1Counts(int a, int b, int k)
{
    int total = a + b;

    vector<Node> memo(total + 1, Node(-1, -1, -1));
    deque<Node> de;

    //将最后一步放入队列
    Node end{total, 0, -1};
    de.push_back(end);
    //每次可能盛夏的
    int remain1;
    memo[total] = Node(total, 0, -1);
    cout << "de add: " << de.back().a << " " 
        << de.back().step << " " << de.size() << endl;
    
    while (!de.empty())
    {
        Node n = de.front();
        cout << "now : " << n.a << " " << n.step << " " << n.f << endl;
        
        //如果目前正在处理的节点,等于初始状态,表明,已经遍历到了最终结果。
        if (n.a == a)
        {
            return n.step;
        }
        de.pop_front();

        cout << "\n_______" << n.a << " :from_______" << endl;
        
        //判断可能的反转情况:
        //反转1变为0的个数:从0到目前的1正面的数目,依次遍历,但不能超过k
        //因为不能一次反转k+1个1,所以,大于的要略去
        for (int i = 0; i <= n.a && i<=k; i++)
        {
            //原有1的个数+每次能反转的K个数-反转的1个数 应该小于总数
            //这里相当于,两个部分叠加,减去重叠部分的长度,不能超过总长
            if (n.a+k-i<=total)
            {
                remain1 = n.a -i + (k-i);
                //记录已经出现,那么就不要在遍历了。
                if (memo[remain1].a == -1)
                {
                    de.push_back(Node(remain1, n.step + 1, n.a));
                    memo[remain1] = Node(remain1, n.step + 1, n.a);
                    cout << "de add: " << de.back().a << " " 
                        << de.back().step << " " << de.size() << endl;
                }
            }
        }
        cout << "_______" << n.a << "_______\n" << endl;
    }
    //上面没有找到可能的反转
    return -1;
}

int main()
{
    int a, b, k;
    cin >> a >> b >> k;
    cout << "count :" << turn0to1Counts(a, b, k) << endl;
}

上面主要在于判断,下一次反转1可能的个数。
理清这个就好了。
(可怜的我,理了一晚上,才搞出来)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 13,002评论 0 33
  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,437评论 0 12
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 180,131评论 25 708
  • 星币皇后 连续第三天抽到星币牌 星币皇后给我的感觉是那么的安稳、沉静, 脚踏在丰沃的土地上,芬芳四溢的鲜花、甜美可...
    snowbear0114阅读 159评论 0 0
  • 打小喜欢猴子,它们抓耳挠腮、上蹿下跳、呲牙裂嘴的模样令人捧腹。在姥姥口中,它们还是一群自以为是的傻家伙! 1、不理...
    荆芥草阅读 302评论 1 8

友情链接更多精彩内容