zoukankan      html  css  js  c++  java
  • 反转 开关问题

    首先考虑最左端的牛。包含这头牛的区间只有一个,因此如果这头牛面朝前方,这个区间不反转,面朝后方则反转。以此类推,逐渐缩小问题规模。

    用数组j[i]=1代表区间[i,i+K-1]进行了反转  j[i]=0代表不反转。

    如果一头牛之前被反转的次数为奇数,则朝向和刚开始相反,为偶数则相同。

    #include<iostream>
    #include<memory.h>
    using namespace std;
    int N,dir[5005];
    int j[5005];   //标记区间[i,i-K+1]是否反转 反转则为1, 不反转为0
    int calc(int K)
    {
        memset(j,0,sizeof(j));
        int res=0; //反转次数
        int sum=0; //j的和 用来表示当前块之前所经历的反转次数
        for(int i=0;i+K<=N;i++)
        {
            //计算区间[i,i-K+1]
            if((dir[i]+sum)%2!=0)//需要进行反转
            {
                j[i]=1;
                res++;
            }
            sum+=j[i];
            if(i-K+1>=0)
            {
                //保持区间长度
                sum-=j[i-K+1];
            }
        }
    
        //检查剩下的K-1头牛是否有朝后的情况
        for(int i=N-K+1;i<N;i++)
        {
            //需要进行反转 无解
            if((dir[i]+sum)%2!=0)
            {
                return -1;
            }
            if(i-K+1>=0)
            {
                //保持区间长度
                sum-=j[i-K+1];
            }
        }
        return res;
    }
    int main()
    {
        cin>>N;
        char c;
        for(int i=0;i<N;i++)
        {
            //牛的方向 0:F 1:B
            cin>>c;
            if(c=='F') dir[i]=0;
            else dir[i]=1;
        }
        //最少操作次数 与之对应的最小操作长度
        int M=N,K=1;
        for(int i=1;i<=N;i++)
        {
            int x=calc(i);
            if(x>0&&x<M)
            {
                K=i;
                M=x;
            }
        }
        cout<<K<<" "<<M<<endl;
        return 0;
    }
    poj3276

    先指定好第一行的翻转方法。此时能够翻转(1,1)的就只剩下(2,1)了,可以直接判断(2,1)是否需要翻转。

    类似的(2,1)~(2,N)都能这样判断,如此反复下去就可以确定所有各自的翻转方法。

    最后(M,1)~(M,N)如果并非全为白色,就意味着不存在可行的操作方法。

    我们需要枚举第一行的所有翻转方法。

    #include<iostream>
    #include<memory.h>
    using namespace std;
    const int dx[5]= {-1,0,0,0,1};
    const int dy[5]= {0,-1,0,1,0};
    int M,N;
    int tile[16][16]; //起始
    int opt[16][16];  //保存最优解
    int flip[16][16]; //保存中间结果
    
    //查询(x,y)的颜色
    int get(int x,int y)
    {
        int c=tile[x][y];
        for(int i=0; i<5; i++)
        {
            int x2=x+dx[i];
            int y2=y+dy[i];
            if(x2>=0&&y2>=0&&x2<M&&y2<N)
            {
                c+=flip[x2][y2];
            }
        }
        return c%2;
    }
    
    //求出第一行确定情况下的最小操作次数
    //不存在解的话返回-1
    int calc()
    {
        //求出从第二行开始的翻转方法
        for(int i=1; i<M; i++)
        {
            for(int j=0; j<N; j++)
            {
                if(get(i-1,j)!=0)
                {
                    //(i-1,j)是黑色的话 必须翻转这个格子
                    flip[i][j]=1;
                }
            }
        }
    
        //判断最后一行是否全白
        for(int j=0; j<N; j++)
        {
            if(get(M-1,j)!=0)
            {
                return -1; //无解
            }
        }
    
        //统计翻转的次数
        int res=0;
        for(int i=0; i<M; i++)
        {
            for(int j=0; j<N; j++)
            {
                res+=flip[i][j];
            }
        }
        return res;
    }
    
    int main()
    {
        cin>>M>>N;
        for(int i=0; i<M; i++)
        {
            for(int j=0; j<N; j++)
            {
                cin>>tile[i][j];
            }
        }
    
        int res=-1;
        //按照字典序尝试第一行的所有可能性
        for(int i=0; i<1<<N; i++)
        {
            memset(flip,0,sizeof(flip));
            for(int j=0; j<N; j++)
            {
                flip[0][N-j-1]=i>>j&1;
            }
            int num=calc();
            if(num>=0&&(res<0||res>num))
            {
                res=num;
                memcpy(opt,flip,sizeof(flip));
            }
        }
    
        if(res<0)
        {
            //无解
            cout<<"IMPOSSIBLE"<<endl;
        }
        else
        {
            for(int i=0; i<M; i++)
            {
                for(int j=0; j<N; j++)
                {
                    cout<<opt[i][j]<<" ";
                }
                cout<<endl;
            }
        }
        return 0;
    }
    poj3279
  • 相关阅读:
    所有时间测试函数
    时间函数应用 time
    50个c/c++源代码网站
    ASN.1详解
    SNMP协议
    SNMP协议详解
    大数据需要建立规则和标准
    常用的三层架构设计
    构建大型网站架构十步骤
    iOS 应用程序内部国际化,不跟随系统语言
  • 原文地址:https://www.cnblogs.com/wangkaipeng/p/6493287.html
Copyright © 2011-2022 走看看