ZJUT 1703 Position Arrangement
题目地址:
http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1703
应谷种同学所发的链接。于是做了一下这道题。不过复习期间忙于数电、自控的复习。某天晚上写了下想法,今天下午写的代码。
一开始是想着找出最多的连续的“1”,然后所有数往这堆连续的“1”靠,不过由于算法基础潺弱,要找这个估计是用最笨的办法,可能早就超时了。
后来想到数据结构与算法分析里的一道题。总之就是第一步先找基准点,第二步再把所有其他的数都往这个基准上靠。
但实际想的过程是相反的。基本上是完全逆向倒推的。首先是最后还剩一个点的时候,必然是这个点往已经集结在一起的“1”靠。再倒推,可知这即是离散的点都往基准点靠。
离散的点比较好办。而本来是一堆的点就比较难办,因为不确定是哪一“堆”往哪一“堆”移动。
假想了以下的场景:
(1)两堆“1”的数量相同,即对称分布,例如00111001110等。这种情况无论是左堆往右堆移,还是反之,亦或是两堆都往中间移,都是一样的。
(2)两堆“1”的数量不同,即非对称分布,例如00110011110,01100111100等。这种情况,则必须是左堆往右堆移。
从另一个角度来看,在最靠两边的两个“1”,即最左/最右的“1”,不可能往左/往右移,只有往右/往左移,或者原地不动;依次类推,左边第2个和右边第2个也是只有往右/往左移或者原地不动。那边到最中间的情况,有可能有两种情况,一种是字符串中有奇数个“1”,则那个在最中间的"1"就是原地不动的,而其他的“1”则向这个中心“1”靠拢。那么这个“1”就是基准点。另一种情况,是有偶数个"1",那么则是左边的所有“1”向中间偏左的“1”靠,右边的也是这样。那么这中间的两个“1”共同构成一个基准,在左右的1都靠到中间这两个半中心“1”后,则到了上面所说的场景(1),即是左半的所有1(包括作为半中心的“1”)往右移一段距离,这段距离是两个半中心“1”间的距离。这样,就找到了基准点。
如上所述,则移动的步骤就是如此。
实际编码,则是用两个数组,一个数组存储input的字符串,另一个数组存储input的字符串中的1出现的位置。然后用ix_mid_prev,ix_mid_next,ix_mid_left,ix_mid_right来存储“下一步移动的1所要到达的位置的旁边的1所在的位置”,并在移动过程中用上述的变量与pos_one中的数(即1未移动时所在的位置)相减,得到移动的步数。
diff则是表示偶数个1中,两个半中心1间的距离。
done
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100002
#define ORDER_MAX 100000
int mov_cnt(char *, int);
int main(void)
{
char str[MAX];
int res[ORDER_MAX];
int i;
int status;
for (i = 0; i < ORDER_MAX; ++i)
{
status = scanf("%s", str);
if (-1 == status)
break;
res[i] = mov_cnt(str, strlen(str));
printf("Case #%d: %d\n", (i+1), res[i]);
}
return 0;
}
int mov_cnt(char *str, int arr_width)
{
int pos_one[arr_width];
int mid, mid_prev, mid_next, ix_mid;
int /*mid_left, mid_right, */diff;
int ix_mid_left, ix_mid_right;
/* int pos_cnt_prev, pos_cnt_next;*/
int pos_cnt = 0;
int cnt_mov = 0;
int pos;
/*first step: find all the postion of '1'*/
for ( pos = 0; pos < arr_width; ++pos)
{
if ('1' == str[pos])
{
pos_one[pos_cnt] = pos;
pos_cnt++;
}
}
/*second step: localize the middle postion of '1'*/
if (pos_cnt % 2) /*the total '1' is odd*/
{
ix_mid = (pos_cnt/2);
mid = pos_one[ix_mid];
/*third step(1):*/
/*left side*/
mid_prev = mid;
for (; ix_mid >= 0; ix_mid--)
{
cnt_mov += mid_prev - pos_one[ix_mid];
mid_prev--;
}
/*right side*/
mid_next = mid;
for (ix_mid = (pos_cnt/2); ix_mid < pos_cnt; ix_mid++)
{
cnt_mov += pos_one[ix_mid] - mid_next;
mid_next++;
}
}
else /*the total '1' is even*/
{
ix_mid_left = pos_cnt/2 - 1;
ix_mid_right = ix_mid_left + 1;
/*third step(2)*/
diff = pos_one[ix_mid_right] - pos_one[ix_mid_left] - 1;
/*left side*/
mid_prev = pos_one[ix_mid_left];
for (; ix_mid_left >= 0; ix_mid_left--)
{
cnt_mov += mid_prev - pos_one[ix_mid_left];
mid_prev--;
}
/*right side*/
mid_next = pos_one[ix_mid_right];
for (; ix_mid_right < pos_cnt; ix_mid_right++)
{
cnt_mov += pos_one[ix_mid_right] - mid_next;
mid_next++;
}
cnt_mov += (pos_cnt/2)*diff;
}
return cnt_mov;
}