zoukankan      html  css  js  c++  java
  • 反转(开关问题) POJ 3276

    POJ 3276

    题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方。问:求最小操作m,再此基础上求k。

    题解:1、5000头牛不是小数目,再怎么也得要n^2的算法,其中,枚举k是需要的,这就有n了,只能想办法给出一个n在O(n)时间内求出最小次数了。

       2、对于给定的k,要想O(n)内把次数算出来,即只能扫一遍,一想到的必定是从前往后扫,遇到面朝后的就转头,但这一转牵扯太多,要改太多东西,k一大直接崩溃。

       3、对于每次扫描到的第i个点,都至多只能改一次才能保证效率,即只改变化的。将牛的朝向弄成依赖型,即后者依赖于前者,这样在一个区间内[a,b]翻转时,实际上[a+1,b]的依赖关系是没有改变的,改变的只有a,b+1。

       4、综上,设置一种关系表示每头牛与前一头牛的朝向,最简单的就是同向与反向的差异,不妨令同向为0,反向为1,为了使得最后都朝前,可以令一头虚拟牛(即0号牛)头朝前,然后第一头牛依赖于它。

       5、因此,每次检查时,只需要更改a和a+k位置的牛的依赖关系便可以解决了,最后在检查一下剩余的牛是否全是0就结束了。

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <memory.h>
    #include <cstring>
    
    
    
    using namespace std;
    
    int N;
    char tmp, tmp1;
    int arr[5002];
    int arr1[5002];
    
    int K,M;
    
    int test(int k)
    {
        memcpy(arr1,arr,sizeof(arr));
        int time = 0;
        for(int i=1; i<=N-k+1; i++)
        {
            if(arr1[i] == 1)
            {
                arr1[i] = 0;
                arr1[i+k] = abs(arr1[i+k]-1);
                time++;
            }
        }
    
        for(int i=N-k+1; i<=N; i++)
        {
            if(arr1[i] == 1)
                return 0;
        }
        return time;
    
    }
    
    
    
    void caculate()
    {
        K = 1;
        M = N;
        int tmpM;
        for(int i=1; i<=N; i++)
        {
            tmpM = test(i);
    
            if(tmpM>0 && tmpM<M)
            {
                M = tmpM;
                K = i;
            }
        }
    
    }
    
    
    
    int main(int argc, char** argv)
    {
    
        //freopen("E:/sample_input.txt", "r", stdin);
    
        while(scanf("%d",&N)!=EOF)
        {
            memset(arr, 0, sizeof(arr));
            tmp1 = 'F';
            for(int i=1; i<=N; i++)
            {
    
                scanf(" %c", &tmp);
                if(tmp == tmp1)
                    arr[i] = 0;
                else
                    arr[i] = 1;
                tmp1 = tmp;
            }
    
            caculate();
    
            cout << K << " " << M << endl;
    
        }
        return 0;
    }
  • 相关阅读:
    界面操作集锦
    测试系列之二如何进行单元测试
    网页右下角弹出广告窗口 超简洁
    如何使一个图片广告悬浮浏览器右下角 右下角图片广告
    zencart网店用的JS弹出广告代码
    zencart数据库清理 让你的网站跑的更快
    Ecrater操作技巧
    网页顶部或者底部广告代码 可定时关闭 可用于网站通知等
    国内出名的外贸B2C网站
    天空之城(献给我喜欢的女孩,杨)
  • 原文地址:https://www.cnblogs.com/scarecrow-blog/p/4572129.html
Copyright © 2011-2022 走看看