POJ 3276 Face The Right Way【枚举】

题意:

N头牛站成一条线,分别朝向前后两个方向,机器可以使连续K头牛同时改变方向,要求所有牛最终朝向前方,问机器操作次数的最小值及此时的最小K值。

分析:

第一眼看感觉是二分搜索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.

是在最小操作的基础上的最小K值,而操作数可达2N个,肯定不能搜索状态了,可以对K进行枚举,算出每次的操作数,进行比较。
直接暴力的话时间复杂度O(n3)过不了,必须进行优化,尽量扫描一遍就获得操作数。
因为是K个连续的一起转,即第ii+k1号牛要一起转,由于这次转动是由第i号牛引起的,就把这次转动体现在a[i]上,令a[i]=1,那么在遍历到第i+k1号牛之前,i+k1号牛所转动的次数就是i+k2ia[i],遍历到第i+k1号牛时,根据求出的转动次数及他本身的方向,判断是否需要转动,依次处理下去。最后判断剩余k1头牛是否全部面向前方。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
using namespace std;
const int maxn = 5005, INF =0x3fffffff;
int s[maxn],a[maxn];
int N;
int judge(int k)
{
    memset(a, 0, sizeof(a));
    int cnt = 0;
    int sum = 0;
    for(int i = 0; i < N - k + 1; i++){
        if((s[i] + sum) % 2 == 1){
            a[i] = 1;
            cnt++;
        }
        sum += a[i];
        if(i-k+1>=0) sum -= a[i-k+1];
    }
    for(int i = N - k +1; i < N; i++){
        if((s[i] + sum) % 2 == 1){
            return -1;
        }
        if(i-k+1>=0) sum -= a[i-k+1];
    }
    return cnt;
}
int main (void)
{
    map<char,int>m;
    m.insert(make_pair('B',1));
    m.insert(make_pair('F',0));
    scanf("%d", &N);
    char c;
    for(int i = 0; i < N;i++){
        getchar();
        c = getchar();
        s[i] = m[c];
    }
    int res = INF, k;
    for(int i = 1; i <= N;i++){
        int ans = judge(i);
        if(ans == -1) continue;
        else if(ans < res){
            res = ans;
            k = i;
        }
    }
    printf("%d %d
", k, res);
}
原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758811.html