二进制翻转的动态规划-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);
            } 

 

posted @ 2014-09-19 15:21  zombies  阅读(366)  评论(0编辑  收藏  举报