1. 01反轉
題目
牛牛正在挑戰(zhàn)一款名為01翻轉的游戲。游戲初始有A個0,B個1,牛牛的目標就是把所有的值都變?yōu)?,每次操作牛牛可以任意選擇恰好K個數(shù)字,并將這K個數(shù)字的值進行翻轉(0變?yōu)?,1變?yōu)?)。牛牛如果使用最少的操作次數(shù)完成這個游戲就可以獲得獎品,牛牛想知道最少的操作次數(shù)是多少?
例如:A = 4 B = 0 K = 30000 -> 1110 -> 1001 -> 0100 -> 1111
需要的最少操作次數(shù)為4
思路
使用廣度優(yōu)先搜索,倒著向后遍歷,從最終狀態(tài)到起始狀態(tài)。
因為每條路徑上邊的全都都可以看作為1,所以如果之前遍歷了,那么之前的一定比后面的路徑(步數(shù))少,所以之前遍歷了,后面再遇到就跳過。
#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的個數(shù)
int step; //距離權為1的步數(shù)
int f; //上次1的個數(shù)
};
//a:1的個數(shù),b:0的個數(shù),k每次反轉的次數(shù)。
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;
//如果目前正在處理的節(jié)點,等于初始狀態(tài),表明,已經(jīng)遍歷到了最終結果。
if (n.a == a)
{
return n.step;
}
de.pop_front();
cout << "\n_______" << n.a << " :from_______" << endl;
//判斷可能的反轉情況:
//反轉1變?yōu)?的個數(shù):從0到目前的1正面的數(shù)目,依次遍歷,但不能超過k
//因為不能一次反轉k+1個1,所以,大于的要略去
for (int i = 0; i <= n.a && i<=k; i++)
{
//原有1的個數(shù)+每次能反轉的K個數(shù)-反轉的1個數(shù) 應該小于總數(shù)
//這里相當于,兩個部分疊加,減去重疊部分的長度,不能超過總長
if (n.a+k-i<=total)
{
remain1 = n.a -i + (k-i);
//記錄已經(jīng)出現(xiàn),那么就不要在遍歷了。
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可能的個數(shù)。
理清這個就好了。
(可憐的我,理了一晚上,才搞出來)