题目要求和分析见题库
这儿只讲一点:p1和p2停下,得到序列,和当前最短序列比较完毕后,class为k-1(k为颜色数)。此时要保持class和color[],p1和p2重复那两个步骤,直至class再次等于k,会再次得到序列,再去和当前最短序列比较,如此循环。程序中止条件是p2越过最后一个元素循环至头一个元素(珠子是首尾相接的)
代码如下:
void shortest_chain(int a[], int n, int k){ //有n个珠子,共k个颜色,颜色代码为0到k-1
assert(a != NULL);
assert(n > 0);
assert(k > 0 && k <= n);
int color[k];
int class = 0;
int p = -1, q = -1;
int len_min = n;
int len_cur;
int start, end;
int over;
memset(color, 0, k*sizeof(int));
while(q < n){
while(class < k){ //移动p将拥有颜色种类增至k
p = (p+1)%n;
if(color[a[p]] == 0) class++;
color[a[p]]++;
}
over = 0;
while(class > k-1){ //移动q将拥有颜色种类降至k-1,此时q和p之间即为候选最短序列
q++;
if(q == n){ //程序中止,如果q再前进相当于重复地从头开始,没有必要
over = 1;
break;
}
color[a[q]]--;
if(color[a[q]] == 0) class--;
}
if(over == 1) break; //程序中止
else{
len_cur = (p >= q) ? p-q+1 : n-(q-p+1)+2; //计算长度,根据p和q的相对大小有两种情况
if(len_cur < len_min){
len_min = len_cur;
start = q;
end = p;
}
}
}
for(int i = start; i <= end; i = (i+1)%n)
printf("%d ", a[i]);
printf("\n");
}