代码:《挑战程序设计竞赛》3.2.2
#include<iostream> using namespace std; #define MAX_N 10000 int N; //牛的个数 int f[MAX_N]; //用于判断区间[i, i + 1 - K]是否进行了反转,区间[i, i + K - 1]进行了反转,f[i]=1,否则为0 int dir[MAX_N]; //牛的方向,0是前,1是后 /*核心思想:如果从标号为i-K+1到i-1的牛的反转次数之和为奇数,则第i头牛的方向与起始方向相同,否则相反,并用sum记录这个值 而标号为i的牛的sum值 = 标号为i-1的牛的sum值 + 标号i的牛的反转次数 - 标号i-K+1的牛的反转次数*/ int calc(int K) //对于固定的K,计算是否有可行解,即对应的最小操作次数 { memset(f, 0, sizeof(f)); int res = 0; //反转次数 int sum = 0; //f的和,用于记录标号为i的牛之前的反转次数 for (int i = 0; i + K <= N; i++) { if ((dir[i] + sum) % 2 != 0) //最左端的牛(标号为i的牛)面向后方(判断方法:标号为i的牛的最初的方向加上该头牛在之前的反转次数,如果为偶数,现在面向的前方,否则为后方) { res++; //反转次数加1 f[i] = 1; //区间[i, i + K - 1]标记为进行了反转 } sum += f[i]; //sum加上区间[i, i + K - 1]的反转次数 if (i - K + 1 >= 0) //如果标号为i的牛位于区间[0, K-1)之后 { sum -= f[i - K + 1]; //sum减去区间[i - K + 1, i]的反转次数,计算标号为i+1的牛的反转次数时不能将其纳入 } } //检查剩余的牛是否有面朝后方的情况 for (int i = N - K + 1; i < N; i++) { if ((dir[i] + sum) % 2 != 0) return -1; //无解 if (i - K + 1 >= 0) //如果标号为i的牛位于区间[0, K-1)之后 { sum -= f[i - K + 1]; //sum减去区间[i - K + 1, i]的反转次数 } } return res; } void solve() { int K = 1, M = N; for (int k = 1; k <= N; k++) { int m = calc(k); if (m >= 0 && M > m) { M = m; K = k; } } cout <<"K = " << K << " " << "M = " << M << endl; } int main() { char direction; cin >> N; for (int i = 0; i < N; i++) { cin >> direction; if (direction == 'B') dir[i] = 1; else dir[i] = 0; } solve(); return 0; } //测试用例 /* 7 BBFBFBB */