二进制翻转的动态规划-TopCoder-SRM598-DIV2-1000pt

题目链接:

http://community.topcoder.com/stat?c=problem_statement&pm=12728&rd=15701

这是个看了题解才会做的题目。

这个题目需要总结出来一些规律:

1)可以用M将整个串分成N/M个组,因为大翻转都是按组为单位的,所以在组的翻转策略被定下来时,内部的翻转都是唯一的,并且可以预计在组的翻转与否确定的情况下需要的组内翻转次数。也就是0或者1的个数。

2)对于以组为单位的翻转,假设翻转的决定是固定的,可以记翻转为1,不翻转为0,表示为一个0-1串。对于这个0-1串,他的最小翻转次数是有规律的:

  1. 如果这个翻转决定为111...1,则翻转次数为1.
  2. 如果其中有0有1,则翻转次数为01间隔的个数。如1010,翻转次数为3.

根据这个结论,就能推导出递推式了:

f (t , p, q) :假定已经确定了[t,n)组的翻转,其中t处的翻转决定为p(0或1),则前t组的最小翻转次数是多少。

q用来标记当前是否是全为111的情况。

子问题就是当前选1或者0时,当前需要花费的翻转开销+f(t-1,p',q')。

其中当前花费的翻转开销分为两部分:

1. 当前是否与之前不一样01间隔。

2. 当前情况下,内部的翻转数。

代码如下:

            vector <int> A;
            vector <int> c[2];
            int dp[2501][2][2];
            int Solve(int t,int p,int q){
                if (dp[t][p][q]!=-1){return dp[t][p][q];}
                if (t==0){    
                    if (p==1 && q==1){        //non-flip at all(q==1) and infact previous choice is 1
                        return 1;
                    }
                    return 0;
                }
                int res=numeric_limits<int>::max();
                //0: flip cur group verse vice
                for (int i=0;i<2;i++){
                    int change=q;        //has a change happened?
                    int curChange=0;    //if current change from previous
                    if (t!=m){
                        curChange=i^p;
                        if (change==1){
                            change=!(p ^ i);
                        }
                    }
                    res=min(res,curChange+c[i][t-1]+Solve(t-1,i,change));
                }
                dp[t][p][q]=res;
                return res;
            }
        int getmin(vector <string> S, int M) 
            { 
                memset(dp,-1,sizeof(dp));
                //devide S into |S|/M groups
                for (int i=0;i<S.size();i++) for (int j=0;j<S[i].length();j++){
                    A.push_back(S[i][j]-'0');
                }
                n=A.size();
                m=n/M;
                c[0].resize(m,0);
                c[1].resize(m,0);
                //statistic the op of flipping or non-flipping bits of every group.
                for (int i=0;i<m;i++) for (int j=0;j<M;j++){
                    int p=i*M+j;
                    if (A[p]==0){c[0][i]++;}
                    else if (A[p]==1){c[1][i]++;}
                }
                //first m groups, last choice is 0, allflip flag is 1
                return Solve(m,0,1);
            } 

 

转载于:https://www.cnblogs.com/yangsc/p/3971890.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值