前言
This Series aritcles are all based on the book 《经典算法大全》; 对于该书的所有案例进行一个探究和拓展,并且用python和C++进行实现; 目的是熟悉常用算法过程中的技巧和逻辑拓展。
提出问题
Algorithm Gossip: 三色棋(Three_Color_Flag)
假设数组里面有若干个3种数 (1,2,3)要大的数靠后,小的数靠前,每次只能调换两个数,问怎么移动让次数最少。
原题目:绳子上有三种三色的旗, “蓝白红”按照这个顺序分离,每次换两个旗。方案让最小换的次数。
分析和解释
在一条绳子上移动,在程式中也就意味只能使用一个阵列,而不使用其它的阵列来作辅助,问 题的解法很简单,您可以自己想像一下在移动旗子,从绳子开头进行,遇到蓝色往前移,遇到 白色留在中间,遇到红色往后移,如下所示: 只是要让移动次数最少的话,就要有些技巧: - 如果图中W所在的位置为白色,则W+1,表示未处理的部份移至至白色群组。 - 如果W部份为蓝色,则B与W的元素对调,而B与W必须各+1,表示两个群组都多了一个元素 。 - 如果W所在的位置是红色,则将W与R交换,但R要减1,表示未处理的部份减1。 注意B、W、R并不是三色旗的个数,它们只是一个移动的指标;什幺时候移动结束呢?一开始 时未处理的R指标会是等于旗子的总数,当R的索引数减至少于W的索引数时,表示接下来的旗 子就都是红色了,此时就可以结束移动
代码
c/c++ 实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BLUE 'b'
#define WHITE 'w'
#define RED 'r'
#define SWAP(x,y) { char temp; \
temp =
color[x]; \
color[x] =
color[y]; \
color[y] = temp; }
int main()
{
char
color[] = {
'r',
'w',
'b',
'w',
'w',
'b',
'r',
'b',
'w',
'r',
'\0'};
int wFlag =
0;
int bFlag =
0;
int rFlag = strlen(
color) -
1;
int i;
for(i =
0; i < strlen(
color); i++)
printf(
"%c ",
color[i]);
printf(
"\n");
while(wFlag <= rFlag) {
if(
color[wFlag] == WHITE)
wFlag++;
else if(
color[wFlag] == BLUE)
{
SWAP(bFlag,wFlag);
bFlag++; wFlag++;
}
else
{
while(wFlag < rFlag &&
color[rFlag] == RED)
rFlag--;
SWAP(rFlag,wFlag);
rFlag--;
}
}
for(i =
0; i < strlen(
color); i++)
printf(
"%c ",
color[i]);
printf(
"\n");
return 0;
}
python 实现
def printc(
color):
for i
in range(len(
color)):
print(
color[i],end =
"")
print()
color = [
'r',
'w',
'b',
'w',
'w',
'b',
'r',
'b',
'w',
'r']
wFlag =
0;
bFlag =
0;
rFlag = len(
color) -
1
printc(
color)
while(wFlag <= rFlag):
if(
color[wFlag] ==
'w'):
wFlag+=
1;
elif(
color[wFlag] ==
'b'):
color[bFlag],
color[wFlag] =
color[wFlag],
color[bFlag]
bFlag+=
1; wFlag+=
1;
else:
while(wFlag < rFlag and
color[rFlag] ==
'r'):
rFlag-=
1
color[rFlag],
color[wFlag] =
color[wFlag],
color[rFlag]
rFlag-=
1;
printc(
color)
拓展和关联
有兴趣的可以尝试下,是不是最优解,用动态规划验证下。
后记
可以向dp状态转变。/后面再深究。
参考书籍
《经典算法大全》维基百科
转载请注明原文地址: https://ju.6miu.com/read-669816.html