• <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 米游 閱讀(907) 評論(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
              回復  更多評論
              
            久久九九久精品国产免费直播| 香蕉aa三级久久毛片| 2022年国产精品久久久久| 无码超乳爆乳中文字幕久久 | 99久久亚洲综合精品网站| 欧美激情精品久久久久| 久久中文精品无码中文字幕 | 久久婷婷综合中文字幕| 久久久久久国产a免费观看不卡| 久久人人添人人爽添人人片牛牛| 久久久精品国产sm调教网站| 久久午夜福利电影| 国产成人精品白浆久久69| 午夜精品久久久久9999高清| 久久婷婷国产麻豆91天堂| 一本久久知道综合久久| 久久久WWW成人免费精品| 久久国产精品成人片免费| 人妻系列无码专区久久五月天| av无码久久久久久不卡网站 | 色综合久久夜色精品国产| 久久国产乱子精品免费女| 日本强好片久久久久久AAA| 欧美日韩精品久久久久| 国产日韩欧美久久| 国产精品一区二区久久| 久久婷婷五月综合色高清| 久久综合亚洲鲁鲁五月天| 亚洲国产成人精品无码久久久久久综合| 亚洲精品乱码久久久久久中文字幕| 韩国三级中文字幕hd久久精品| 成人免费网站久久久| 欧美午夜精品久久久久免费视| 久久婷婷色综合一区二区| 秋霞久久国产精品电影院| 99久久久精品免费观看国产| 久久66热人妻偷产精品9| 久久99精品国产麻豆宅宅| 人妻无码精品久久亚瑟影视| 欧美亚洲国产精品久久久久| 日韩久久久久中文字幕人妻|