POJ 3276 Face The Right Way(反转)

Description
n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方。问:求最小操作m,再此基础上求k
Input
第一行一个整数n表示牛数,之后n行每行一个字母表示牛的朝向,F表示朝前,B表示朝后
Output
输出k和m
Sample Input
7
B
B
F
B
F
B
B
Sample Output
3 3
Solution
首先对所有的k都求解一次,对于每个k都从最左端开始来考虑n头牛的情况。此时最坏情况下需要进行n-k+1此反转,而每次操作又要反转k头牛,此时时间复杂度为O(n^3),显然超时,所以在反转部分做优化,令f[i]:区间[i,i+k-1]进行反转则为1,否则为0
这样,在考虑第i头牛的时候,如果这里写图片描述为奇数的话,那么这头牛的方向与起始方向相反,否则方向不变,由于这里写图片描述,所以这个和每一次都可以在常数时间计算出来,复杂度降到了O(n^2),能够在时限内解决
Code

#include<stdio.h>
#include<string.h>
#define maxn 5001
int n,dir[maxn];//牛的方向(0:F,1:B) 
int f[maxn];//区间[i,i+k-1]是否进行反转 
int solve(int k)//固定k,求最少操作次数,无解返回-1 
{
    memset(f,0,sizeof(f));//初始化 
    int res=0;
    int sum=0;//f的和 
    int i;
    for(i=0;i+k<=n;i++)//计算区间[i,i+k-1] 
    {
        if((dir[i]+sum)%2!=0)//前端的牛朝后 
        {
            res++;
            f[i]=1;
        }
        sum+=f[i];
        if(i-k+1>=0)
            sum-=f[i-k+1];
    }   
    for(i=n-k+1;i<n;i++)//检查剩下的牛是否有朝后的情况 
    {
        if((dir[i]+sum)%2!=0)//无解 
            return -1;
        if(i-k+1>=0)
            sum-=f[i-k+1];
    }
    return res;
}

int main()
{
    scanf("%d",&n);
    getchar();
    char c;
    int i;
    for(i=0;i<n;i++)
    {
        scanf("%c",&c);
        getchar();
        if(c=='F')
            dir[i]=0;
        else
            dir[i]=1;
    }
    int m=n,k=1;
    for(i=1;i<=n;i++)
    {
        int t=solve(i);
        if(t>=0&&m>t)//更新最小操作数 
        {
            m=t;
            k=i;
        }
    }
    printf("%d %d\n",k,m);
    return 0;
}

你可能感兴趣的:(POJ 3276 Face The Right Way(反转))