• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-38  評論-23  文章-0  trackbacks-0


            題目中文不解釋了。
            剛開始做這題,我想到的就是遞歸.因為子問題與大問題完全一樣..
            于是連公式都未化簡,寫了個遞歸程序。測試的時候發(fā)現(xiàn)n越大,我的程序就很慢才得出結(jié)果了..
            遞歸的函數(shù)是這么寫的
            double getMinr(int mini,int maxi,int minj,int maxj,int k) // 表示這個矩形塊分割成k塊的最小均方差.

            double getMinr(int mini,int maxi,int minj,int maxj,int k,int sum)
            {
                
            int s=0;
                
            double minr=0x7fffffff,res;
                
            if(k==1)
                
            {
                    
            return (sum-xb)*(sum-xb)/n;
                }

                
            for(int i=mini+1;i<maxi;i++)
                
            {
                    s
            =0;
                    
            for(int l=mini;l<i;l++)
                        
            for(int m=minj;m<maxj;m++)
                            s
            +=chess[l][m];
                    res
            =getMinr(mini,i,minj,maxj,k-1,s)+(sum-s-xb)*(sum-s-xb)/n;
                    
            if(res<minr) minr=res;
                    res
            =getMinr(i,maxi,minj,maxj,k-1,sum-s)+(s-xb)*(s-xb)/n;
                    
            if(res<minr) minr=res;
                }

                
            for(int i=minj+1;i<maxj;i++)
                
            {
                    s
            =0;
                    
            for(int l=mini;l<maxi;l++)
                        
            for(int m=minj;m<i;m++)
                            s
            +=chess[l][m];
                    res
            =getMinr(mini,maxi,minj,i,k-1,s)+(sum-s-xb)*(sum-s-xb)/n;
                    
            if(res<minr) minr=res;
                    res
            =getMinr(mini,maxi,i,maxj,k-1,sum-s)+(s-xb)*(s-xb)/n;
                    
            if(res<minr) minr=res;
                }

                
            return minr;
            }

            結(jié)果發(fā)現(xiàn)測試數(shù)據(jù)時候,發(fā)現(xiàn)會超時.
            所以開始采用記憶化搜索.并且發(fā)現(xiàn)公式可以化簡 (xi-xb)*(xi-xb) =xi*xi-2*xi*xb+xb*xb 最后可以將
            均方差的平方剛好等于 sum(xi*xi)/n-xb*xb
            并且在搜索前記錄好值.
            這時候代碼如下所示。依然TLE...
            #include<iostream>
            #include
            <cmath>
            using namespace std;
            int chess[8][8],n;
            int minresult[15][9][9][9][9];//保存結(jié)果
            int sm[9][9]; //表示從1行1列到i行j列所有數(shù)據(jù)的總和.
            const int INF=10000000;
            int getMinr(int mini,int maxi,int minj,int maxj,int k)
            {
                
            int s=0,sum=0;
                
            int  res,minr=INF;
                sum
            =sm[maxi][maxj]-sm[mini][maxj]-sm[maxi][minj]+sm[mini][minj];
                
            if(k==1)
                
            {
                    minresult[k][mini][maxi][minj][maxj]
            =sum*sum;
                    
            return minresult[k][mini][maxi][minj][maxj];
                }

                
            if(minresult[k][mini][maxi][minj][maxj]!=INF)
                    
            return minresult[k][mini][maxi][minj][maxj];
                
            for(int i=mini+1;i<maxi;i++)
                
            {
                    s
            =sm[i][maxj]-sm[mini][maxj]-sm[i][minj]+sm[mini][minj];
                    res
            =getMinr(mini,i,minj,maxj,k-1)+(sum-s)*(sum-s);
                    
            if(res<minr) minr=res;
                    res
            =getMinr(i,maxi,minj,maxj,k-1)+s*s;
                    
            if(res<minr) minr=res;
                }

                
            for(int i=minj+1;i<maxj;i++)
                
            {
                    s
            =sm[maxi][i]-sm[mini][i]-sm[maxi][minj]+sm[mini][minj];
                    res
            =getMinr(mini,maxi,minj,i,k-1)+(sum-s)*(sum-s);
                    
            if(res<minr) minr=res;
                    res
            =getMinr(mini,maxi,i,maxj,k-1)+s*s;
                    
            if(res<minr) minr=res;
                }

                minresult[k][mini][maxi][minj][maxj]
            =minr;
                
            return minr;
            }

            int main()
            {
                
            double result;
                
            while(cin>>n)
                
            {
                
            for(int i=0;i<8;i++)
                    
            for(int j=0;j<8;j++)
                        scanf(
            "%d",&chess[i][j]);
                
            for(int i=1;i<8;i++)
                    sm[
            0][i]=0,sm[i][0]=0;
                
            for(int i=1;i<=8;i++)
                
            {    
                    
            int temp=0;
                    
            for(int j=1;j<=8;j++)
                    
            {
                        temp
            +=chess[i-1][j-1];
                        sm[i][j]
            =sm[i-1][j]+temp; 
                    }

                }

                
            for(int k=1;k<=n;k++)
                    
            for(int i=0;i<9;i++)
                        
            for(int j=0;j<9;j++)
                            
            for(int l=0;l<9;l++)
                                
            for(int m=0;m<9;m++)
                                    minresult[k][i][j][l][m]
            =INF;
                
            int m=getMinr(0,8,0,8,n);
                result
            =m*1.0/n-sm[8][8]*sm[8][8]*1.0/(n*n);
                printf(
            "%.3lf\n",sqrt(result));
                }

            }




            經(jīng)過以上的分析之后,終于明白必須得將遞歸表達(dá)式轉(zhuǎn)化成自底向上的DP去解決...
            #include<iostream>
            #include
            <cmath>
            using namespace std;
            int chess[8][8],n;
            int minresult[15][9][9][9][9];//保存結(jié)果
            int sm[9][9];//保存從0,0-i-1,j-1的矩形塊的數(shù)據(jù)和
            const int INF=10000000;
            int getMinr(int k,int mini,int minj,int maxi,int maxj)
            {
                
            int res,s,minr=INF,sum;
                sum
            =sm[maxi][maxj]-sm[mini][maxj]-sm[maxi][minj]+sm[mini][minj];
                
            for(int i=mini+1;i<maxi;i++)
                
            {
                    s
            =sm[i][maxj]-sm[mini][maxj]-sm[i][minj]+sm[mini][minj];
                    res
            =minresult[k][mini][minj][i][maxj]+(sum-s)*(sum-s);
                    
            if(res<minr) minr=res;
                    res
            =minresult[k][i][minj][maxi][maxj]+s*s;
                    
            if(res<minr) minr=res;
                }

                
            for(int i=minj+1;i<maxj;i++)
                
            {
                    s
            =sm[maxi][i]-sm[mini][i]-sm[maxi][minj]+sm[mini][minj];
                    res
            =minresult[k][mini][minj][maxi][i]+(sum-s)*(sum-s);
                    
            if(res<minr) minr=res;
                    res
            =minresult[k][mini][i][maxi][maxj]+s*s;
                    
            if(res<minr) minr=res;
                }

                
            return minr;
            }

            int main()
            {
                
            double result;
                
            while(cin>>n)
                
            {
                
            for(int i=0;i<8;i++)
                    
            for(int j=0;j<8;j++)
                        scanf(
            "%d",&chess[i][j]);
                
            for(int i=1;i<8;i++)
                    sm[
            0][i]=0,sm[i][0]=0;
                
            for(int i=1;i<=8;i++)
                
            {    
                    
            int temp=0;
                    
            for(int j=1;j<=8;j++)
                    
            {
                        temp
            +=chess[i-1][j-1];
                        sm[i][j]
            =sm[i-1][j]+temp;
                    }

                }

                
            for(int k=1;k<=n;k++)
                    
            for(int i=0;i<9;i++)
                        
            for(int j=0;j<9;j++)
                            
            for(int l=0;l<9;l++)
                                
            for(int m=0;m<9;m++)
                                    minresult[k][i][j][l][m]
            =INF;
                
            int m=getMinr(0,8,0,8,n);
                
            for(int mini=0;mini<9;mini++//行從第mini行開始
                    for(int minj=0;minj<9;minj++)//列從第minj列開始
                        for(int maxi=mini+1;maxi<9;maxi++//按第maxi行分割
                            for(int maxj=minj+1;maxj<9;maxj++)//按第maxj列分割 這樣組成一塊小矩形區(qū)域
                            {
                                
            int temp=sm[maxi][maxj]-sm[mini][maxj]-sm[maxi][minj]+sm[mini][minj];
                                minresult[
            1][mini][minj][maxi][maxj]=temp*temp;
                            }


                
            for(int k=2;k<=n;k++)
                    
            for(int mini=0;mini<9;mini++//行從第mini行開始
                        for(int minj=0;minj<9;minj++)//列從第minj列開始
                            for(int maxi=mini+1;maxi<9;maxi++//按第maxi行分割
                                for(int maxj=minj+1;maxj<9;maxj++)//按第maxj列分割 這樣組成一塊小矩形區(qū)域
                                    minresult[k][mini][minj][maxi][maxj]=getMinr(k-1,mini,minj,maxi,maxj);
                m
            =minresult[n][0][0][8][8];
                result
            =m*1.0/n-sm[8][8]*sm[8][8]*1.0/(n*n);
                printf(
            "%.3lf\n",sqrt(result));
                }

            }




            這次收獲頗大....DP的狀態(tài)剛好與遞歸的參數(shù)一致!


            最后說下. 這天下午我讓我朋友參謀上面的那段遞歸記憶化搜索的代碼。。發(fā)現(xiàn)其實可以過的。。而修改只要在一個地方...
            初始化 memset(minresult,0,sizeof(minresult));
            在遞歸的時候判斷
             if(minresult[k][mini][maxi][minj][maxj])
                    return minresult[k][mini][maxi][minj][maxj];
            就可以過了 0ms。。納悶中。。。
            初始化最大的時候可能會遇到這種情況..minresult還是會等于INF 而會一直遞歸..
            最后的收獲就是 最好在遞歸的時候用最簡單的狀態(tài)來判斷是否被搜索過了!!!!
            posted on 2009-04-01 12:15 米游 閱讀(899) 評論(4)  編輯 收藏 引用 所屬分類: ACM

            評論:
            # re: pku 1191 棋盤分割 (DP)(三) 2009-08-22 11:09 | sakuratest
            真的受益匪淺。代碼從高復(fù)雜度向低復(fù)雜度的思路條理非常清晰,代碼格式也很好,注釋雖然不多,但很清晰。很好的學(xué)習(xí)文!!!  回復(fù)  更多評論
              
            # re: pku 1191 棋盤分割 (DP)(三)[未登錄] 2009-08-22 13:13 | 米游
            @sakuratest
            這是以前寫代碼所沒有注意到的一個好習(xí)慣>_< 不寫注釋。。現(xiàn)在的代碼好多了。可惜我已經(jīng)好久沒有做ACM的題了  回復(fù)  更多評論
              
            # re: pku 1191 棋盤分割 (DP)(三) 2009-09-09 08:14 | shizu
            請問下,如果這題同時要你輸出每個分割的數(shù)組坐標(biāo),即左上起始坐標(biāo)和右下中止坐標(biāo),自下而上的方法似乎就有問題了吧~~請指教!!謝謝~  回復(fù)  更多評論
              
            # re: pku 1191 棋盤分割 (DP)(三) 2009-09-12 11:22 | 米游
            我覺得你完全可以在getMinr()這個函數(shù)中記錄你想要的起始和終止坐標(biāo),因為分成K個區(qū)域.會從K-1個區(qū)域中得來..因此.你完全可以在getMinr()記錄這個區(qū)域.因為其中計算res的時候本身就是一個區(qū)域值?
            @shizu
              回復(fù)  更多評論
              
            久久久WWW成人免费精品| 久久精品成人一区二区三区| 国产欧美久久久精品| 久久中文字幕人妻熟av女| 国产91久久综合| 五月丁香综合激情六月久久| 欧美亚洲日本久久精品| 欧美久久综合性欧美| 久久久久亚洲AV片无码下载蜜桃| 亚洲伊人久久成综合人影院| 伊人色综合久久天天| A狠狠久久蜜臀婷色中文网| 无码人妻精品一区二区三区久久久| 色综合久久88色综合天天 | 色综合久久久久| 国产精品亚洲美女久久久| 国产三级精品久久| 亚洲综合婷婷久久| 国产精品永久久久久久久久久| 狠狠干狠狠久久| 国产精品久久久久久久午夜片| 久久综合丁香激情久久| 7国产欧美日韩综合天堂中文久久久久 | 伊人久久大香线蕉综合网站| 久久成人永久免费播放| 亚洲国产成人久久综合一区77| 天堂无码久久综合东京热| 日韩十八禁一区二区久久| 国内精品久久久久影院亚洲| 99精品国产99久久久久久97| 午夜天堂精品久久久久| 91精品国产91久久久久久| 婷婷久久综合九色综合绿巨人| 国产激情久久久久久熟女老人| 国产精品一久久香蕉产线看| 99久久无码一区人妻| 国产精品久久久香蕉| 国产 亚洲 欧美 另类 久久| 77777亚洲午夜久久多喷| 久久综合九色综合久99| 久久天天躁狠狠躁夜夜2020一|