Face The Right Way(开关问题)

代码:《挑战程序设计竞赛》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
*/
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值