POJ3276-翻转奶牛

题目

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.

Input

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.

Output

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

Sample Input

7
B
B
F
B
F
B
B

Sample Output

3 3

Hint

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

题目意思

其实就是给你n个奶牛,他们的朝向有向后和先前,现在你可以翻转这些奶牛,每次必须连续翻转K个,现在让找到一个K使得翻转次数最少,从而能够使所有的奶牛都朝前。

思路

我们可以采用尺取法来做此题,其实也可以理解为动态规划。长度为K的尺子维护了一个此区间的总共翻转次数。我们首先记录初始奶牛的状态,0表示向前,1表示向后。
从1到n开始枚举k,初始翻转次数为0。然后我们根据奶牛的初始状态加上尺子区间内总共的翻转次数来判断当前位置是否已朝前。若未朝前,则当前位置翻转1次,记录该位置翻转了。然后判断当前扩展的长度是否已达到了尺子的最大长度,若是,则要去掉开头第一个的贡献,因为我们下次要先后扩展一个,且开头第一个的贡献影响不到尺子最大长度的后一个位置。
由于每次翻转必须翻转k位,所以对于最后的k - 1位,不能翻转了,只能判断之前的贡献是否能使这些奶牛朝前,从而判断k是否合法。

代码

package com.special.POJ;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * POJ3276
 * 尺取法
 * 维护一个长度为K的翻转次数即可
 * Created by Special on 2018/4/21 23:53
 */
public class POJ3276 {

    public static void main(String[] args){
        FastScanner input = new FastScanner();
        PrintWriter out = new PrintWriter(System.out);
        int n = input.nextInt();
        int[] dir = new int[n];
        int[] flag = new int[n];
        for(int i = 0; i < n; i++){
            dir[i] = (input.next().equals("F")) ? 0 : 1;//记录是否需要翻转
        }
        int ansK = Integer.MAX_VALUE, ansN = Integer.MAX_VALUE;
        for(int k = 1; k <= n; k++){
            int sum = 0;
            int cnt = 0;
            Arrays.fill(flag, 0);
            for(int i = 0; i <= n - k; i++){
                if(((dir[i] + sum) & 1) == 1){ //需要翻转加上之前的翻转对本位置的影响
                    flag[i] = 1;
                    sum++;
                    cnt++;
                }
                if(i - k + 1 >= 0){//若尺子的长度已达到K,则要去掉尺子第一位的贡献
                    sum -= flag[i - k + 1];
                }
            }
            // n - k + 1 到 n之间,因为长度小于k,所以无法翻转,只能靠之前的贡献
            for(int i = n - k + 1; i < n; i++){
                if(((dir[i] + sum) & 1) == 1){ //若不满足朝前,说明之前的翻转不满足
                    cnt = -1;
                    break;
                }
                if(i - k + 1 >= 0) {sum -= flag[i - k + 1];}
            }
            if(~cnt != 0 && cnt < ansN){
                ansN = cnt;
                ansK = k;
            }
        }
        out.println(ansK + " " + ansN);
        out.close();
    }
    //快速IO
    static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner() {
            try {
                br = new BufferedReader(new InputStreamReader(System.in));
                st = new StringTokenizer(br.readLine());
            } catch (Exception e){e.printStackTrace();}
        }

        public String next() {
            if (st.hasMoreTokens()) return st.nextToken();
            try {st = new StringTokenizer(br.readLine());}
            catch (Exception e) {e.printStackTrace();}
            return st.nextToken();
        }

        public int nextInt() {return Integer.parseInt(next());}

        public long nextLong() {return Long.parseLong(next());}

        public double nextDouble() {return Double.parseDouble(next());}

        public String nextLine() {
            String line = "";
            if(st.hasMoreTokens()) line = st.nextToken();
            else try {return br.readLine();}catch(IOException e){e.printStackTrace();}
            while(st.hasMoreTokens()) line += " "+st.nextToken();
            return line;
        }
    }
}

参考

  1. https://blog.csdn.net/qq_34374664/article/details/53028870

你可能感兴趣的:(不刷题心里难受,动态规划)