• <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


            題目中文不解釋了。
            剛開始做這題,我想到的就是遞歸.因為子問題與大問題完全一樣..
            于是連公式都未化簡,寫了個遞歸程序。測試的時候發現n越大,我的程序就很慢才得出結果了..
            遞歸的函數是這么寫的
            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;
            }

            結果發現測試數據時候,發現會超時.
            所以開始采用記憶化搜索.并且發現公式可以化簡 (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];//保存結果
            int sm[9][9]; //表示從1行1列到i行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));
                }

            }




            經過以上的分析之后,終于明白必須得將遞歸表達式轉化成自底向上的DP去解決...
            #include<iostream>
            #include
            <cmath>
            using namespace std;
            int chess[8][8],n;
            int minresult[15][9][9][9][9];//保存結果
            int sm[9][9];//保存從0,0-i-1,j-1的矩形塊的數據和
            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列分割 這樣組成一塊小矩形區域
                            {
                                
            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列分割 這樣組成一塊小矩形區域
                                    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的狀態剛好與遞歸的參數一致!


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

            評論:
            # re: pku 1191 棋盤分割 (DP)(三) 2009-08-22 11:09 | sakuratest
            真的受益匪淺。代碼從高復雜度向低復雜度的思路條理非常清晰,代碼格式也很好,注釋雖然不多,但很清晰。很好的學習文!!!  回復  更多評論
              
            # re: pku 1191 棋盤分割 (DP)(三)[未登錄] 2009-08-22 13:13 | 米游
            @sakuratest
            這是以前寫代碼所沒有注意到的一個好習慣>_< 不寫注釋。。現在的代碼好多了。可惜我已經好久沒有做ACM的題了  回復  更多評論
              
            # re: pku 1191 棋盤分割 (DP)(三) 2009-09-09 08:14 | shizu
            請問下,如果這題同時要你輸出每個分割的數組坐標,即左上起始坐標和右下中止坐標,自下而上的方法似乎就有問題了吧~~請指教!!謝謝~  回復  更多評論
              
            # re: pku 1191 棋盤分割 (DP)(三) 2009-09-12 11:22 | 米游
            我覺得你完全可以在getMinr()這個函數中記錄你想要的起始和終止坐標,因為分成K個區域.會從K-1個區域中得來..因此.你完全可以在getMinr()記錄這個區域.因為其中計算res的時候本身就是一個區域值?
            @shizu
              回復  更多評論
              
            久久精品国产清自在天天线| 日韩精品久久无码人妻中文字幕| 久久国产AVJUST麻豆| 99久久这里只有精品| 精品人妻久久久久久888| 久久香蕉超碰97国产精品| 精品人妻伦九区久久AAA片69| 人妻中文久久久久| 久久久久国色AV免费观看| 国产精品日韩深夜福利久久| 九九久久99综合一区二区| 狠色狠色狠狠色综合久久| 久久久久国产一级毛片高清版| 国产精品久久国产精品99盘| 国内精品伊人久久久久av一坑| 久久久久久国产精品免费无码| 久久久久无码精品国产| 精品午夜久久福利大片| 精品久久久久中文字| 一个色综合久久| 久久久久99精品成人片试看| 91精品国产综合久久久久久| 久久福利青草精品资源站| 久久www免费人成精品香蕉| 日韩欧美亚洲综合久久影院Ds| 久久久久青草线蕉综合超碰| 日日噜噜夜夜狠狠久久丁香五月| 久久久久久久综合日本亚洲| 久久久久久国产精品免费免费| 亚洲综合精品香蕉久久网| 狠狠色丁香久久婷婷综合五月| 精品久久综合1区2区3区激情| 无码任你躁久久久久久老妇| 欧美大香线蕉线伊人久久| a级毛片无码兔费真人久久| 奇米影视7777久久精品人人爽| 国内精品久久久久久99蜜桃 | 久久亚洲AV成人无码电影| 久久成人影院精品777| 亚洲级αV无码毛片久久精品| 91精品国产高清久久久久久国产嫩草|