• <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  評(píng)論-23  文章-0  trackbacks-0


            題目中文不解釋了。
            剛開始做這題,我想到的就是遞歸.因?yàn)樽訂栴}與大問題完全一樣..
            于是連公式都未化簡,寫了個(gè)遞歸程序。測試的時(shí)候發(fā)現(xiàn)n越大,我的程序就很慢才得出結(jié)果了..
            遞歸的函數(shù)是這么寫的
            double getMinr(int mini,int maxi,int minj,int maxj,int k) // 表示這個(gè)矩形塊分割成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ù)時(shí)候,發(fā)現(xiàn)會(huì)超時(shí).
            所以開始采用記憶化搜索.并且發(fā)現(xiàn)公式可以化簡 (xi-xb)*(xi-xb) =xi*xi-2*xi*xb+xb*xb 最后可以將
            均方差的平方剛好等于 sum(xi*xi)/n-xb*xb
            并且在搜索前記錄好值.
            這時(shí)候代碼如下所示。依然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)其實(shí)可以過的。。而修改只要在一個(gè)地方...
            初始化 memset(minresult,0,sizeof(minresult));
            在遞歸的時(shí)候判斷
             if(minresult[k][mini][maxi][minj][maxj])
                    return minresult[k][mini][maxi][minj][maxj];
            就可以過了 0ms。。納悶中。。。
            初始化最大的時(shí)候可能會(huì)遇到這種情況..minresult還是會(huì)等于INF 而會(huì)一直遞歸..
            最后的收獲就是 最好在遞歸的時(shí)候用最簡單的狀態(tài)來判斷是否被搜索過了!!!!
            posted on 2009-04-01 12:15 米游 閱讀(921) 評(píng)論(4)  編輯 收藏 引用 所屬分類: ACM

            評(píng)論:
            # re: pku 1191 棋盤分割 (DP)(三) 2009-08-22 11:09 | sakuratest
            真的受益匪淺。代碼從高復(fù)雜度向低復(fù)雜度的思路條理非常清晰,代碼格式也很好,注釋雖然不多,但很清晰。很好的學(xué)習(xí)文!!!  回復(fù)  更多評(píng)論
              
            # re: pku 1191 棋盤分割 (DP)(三)[未登錄] 2009-08-22 13:13 | 米游
            @sakuratest
            這是以前寫代碼所沒有注意到的一個(gè)好習(xí)慣>_< 不寫注釋。。現(xiàn)在的代碼好多了。可惜我已經(jīng)好久沒有做ACM的題了  回復(fù)  更多評(píng)論
              
            # re: pku 1191 棋盤分割 (DP)(三) 2009-09-09 08:14 | shizu
            請(qǐng)問下,如果這題同時(shí)要你輸出每個(gè)分割的數(shù)組坐標(biāo),即左上起始坐標(biāo)和右下中止坐標(biāo),自下而上的方法似乎就有問題了吧~~請(qǐng)指教!!謝謝~  回復(fù)  更多評(píng)論
              
            # re: pku 1191 棋盤分割 (DP)(三) 2009-09-12 11:22 | 米游
            我覺得你完全可以在getMinr()這個(gè)函數(shù)中記錄你想要的起始和終止坐標(biāo),因?yàn)榉殖蒏個(gè)區(qū)域.會(huì)從K-1個(gè)區(qū)域中得來..因此.你完全可以在getMinr()記錄這個(gè)區(qū)域.因?yàn)槠渲杏?jì)算res的時(shí)候本身就是一個(gè)區(qū)域值?
            @shizu
              回復(fù)  更多評(píng)論
              
            青青青青久久精品国产| 久久免费视频1| 国产成人精品综合久久久| 久久青青草原精品国产不卡| 青青草国产97免久久费观看| 亚洲午夜久久久影院伊人| MM131亚洲国产美女久久| 久久国产成人亚洲精品影院| 久久无码国产专区精品| 伊人热人久久中文字幕| 久久久这里只有精品加勒比| 狠色狠色狠狠色综合久久| 日本精品久久久久影院日本| 久久精品国产亚洲av麻豆蜜芽| 韩国无遮挡三级久久| 国产A三级久久精品| a级毛片无码兔费真人久久| 亚洲精品乱码久久久久66| 国产精品美女久久久网AV| 97精品国产97久久久久久免费| 99久久国产热无码精品免费久久久久 | 久久er国产精品免费观看2| 天堂无码久久综合东京热| 久久久精品免费国产四虎| 久久久久久亚洲精品无码| 久久99国产乱子伦精品免费| 欧美伊香蕉久久综合类网站| aaa级精品久久久国产片| 99久久香蕉国产线看观香 | 久久精品国产欧美日韩| 亚洲人成无码网站久久99热国产| 国产99久久精品一区二区| 婷婷久久综合| 99久久www免费人成精品| 99久久综合狠狠综合久久止| 久久久亚洲AV波多野结衣 | 中文字幕久久精品| 久久久免费精品re6| 中文精品99久久国产| 国产精品九九久久免费视频 | 亚洲国产欧美国产综合久久|