洛谷P2882 [USACO07MAR]Face The Right Way G 贪心思想的数学证明

题目

题目描述

Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing forward, like good cows. Some of them are facing backward, though, and he needs them all to face forward to make his life perfect.

Fortunately, FJ recently bought an automatic cow turning machine. Since he purchased the discount model, it must be irrevocably preset to turn K (1 ≤ K ≤ N) cows at once, and it can only turn cows that are all standing next to each other in line. Each time the machine is used, it reverses the facing direction of a contiguous group of K cows in the line (one cannot use it on fewer than K cows, e.g., at the either end of the line of cows). Each cow remains in the same *location* as before, but ends up facing the *opposite direction*. A cow that starts out facing forward will be turned backward by the machine and vice-versa.

Because FJ must pick a single, never-changing value of K, please help him determine the minimum value of K that minimizes the number of operations required by the machine to make all the cows face forward. Also determine M, the minimum number of machine operations required to get all the cows facing forward using that value of K.

N 头牛排成一列(1<=N<=5000)。每头牛或者向前或者向后。为了让所有牛都面向前方,农夫每次可以将 KK 头连续的牛转向 1<=K<=N,求使操作次数最小的相应 K 和最小的操作次数 M。F 为朝前,B 为朝后。

请在一行输出两个数字 K 和 M,用空格分开。

输入格式

Line 1: A single integer: N

Lines 2..N+1: Line i+1 contains a single character, F or B, indicating whether cow i is facing forward or backward.

输出格式

Line 1: Two space-separated integers: K and M

输入输出样例

输入 #1

7
B
B
F
B
F
B
B

输出 #1

3 3

说明/提示

For K = 3, the machine must be operated three times: turn cows (1,2,3), (3,4,5), and finally (5,6,7)

题解

(引自Delva)

贪心,枚举,差分

因为同一个点翻转两次就与没有翻转的效果相同了,因此我们有一个贪心策略为:

从左到右对于出现的每一个B翻转一次从当前点开始的区间,就能保证是最优解。

样例的模拟:

如果当前翻转的区间长度为3

粗体表示当前下标

B B F B F B B

(B B F) B F B B

F F B B F B B

F B B F B B

F F B B F B B

F F (B B F) B B

F F F F B B B

F F F F B B B

F F F F B B B

F F F F (B B B)

F F F F F F F

F F F F F F F

F F F F F F F

但是我们会发现这样是n^2的,再枚举长度,就变为了n^3.因此,需要对区间翻转差分一下,总时间复杂度就是n^2的了。

代码(自己实现) 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#ifndef INT_MAX
#define INT_MAX 0x7fffffff
#endif

using namespace std;

const int MAXN = 5005;
int N, M = INT_MAX, ans;
bool a[MAXN], b[MAXN];

int main()
{
    cin >> N;
    for(int i = 1; i <= N; ++i)
    {
        char ch;
        cin >> ch;
        a[i] = ch == 'F';
    }
    for(int K = 1; K <= N; ++K)
    {
        memset(b, 0, sizeof(b)); // b:差分数组
        bool succ = true, g = false;
        int cnt = 0;
        for(int i = 1; i <= N; ++i)
        {
            g ^= b[i]; // '^'相当于'+'或'-'
            if((a[i] ^ g) == false)
            {
                if(i + K - 1 > N)
                {
                    succ = false;
                    break;
                }
                g ^= 1;
                b[i + K] ^= 1;
                ++cnt;
            }
        }
        if(succ)
        {
            if(cnt < M)
            {
                M = cnt;
                ans = K;
            }
        }
    }
    printf("%d %d\n", ans, M);
    return 0;
}

贪心思想数学证明

定理1 对于任意K(1<=K<=N),下面的算法总能使翻转次数最小:

从前往后扫描每只牛,只要发现某只牛朝后,那么就把以这只牛为首的K只牛转向。

同时,如果发现剩余的牛的数量小于K,那么这个K一定不可行。

证明:采用数学归纳法

 ① 当N=K时,若所有牛都朝前,则命题显然成立。

若所有牛都朝后,命题亦显然成立。

若非所有牛朝前或朝后,则不论翻转多少次,总有一部分牛朝前,一部分牛朝后,因此K不可行,命题成立。

② 假设当N=K到L时命题都成立。则当N=L+1时:

(1) 若第一头牛朝前,则这一步不用翻转,往后找到向后的牛(如果存在),假设从这头牛到最后一头牛共有P头,由于K<=P<=L(当P<K时命题K不可行,命题成立),当N=P时所做的翻转最少,因此在N=L+1时所做的翻转仍为最少,故命题成立。

(2) 若第一头牛朝后,则必须翻转以该头牛为首的K头牛。翻转之后往后找到朝后的牛,假设从这头牛到最后一头牛共有P头,正如我们刚才提到的,N=P时命题成立。由于第一头牛朝后,故必须翻转至少一次,而我们只在P头牛的基础上翻转了一次,故仍为最优。

证毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值