【洛谷2217】[HAOI2007] 分割矩陣(DP水題)
阿新 • • 發佈:2020-11-03
- 給定一個\(a\times b\)的矩陣,要求你對它進行\(n-1\)次劃分,每次把一個矩陣按某一行或某一列分成兩個。
- 求這\(n\)個矩陣各自元素和的最小均方差。
- \(a,b,n\le10\)
\(DP\)水題
首先考慮均方差為:
\[\sqrt{\frac{\sum_{i=1}^n(S_i-\bar{S})^2}n} \]顯然,\(\bar{S}=\frac {\sum s_{i,j}}{n}\)是一個定值,不妨設\(\sum s_{i,j}=tot\),得到:
\[\sqrt{\frac{\sum_{i=1}^n(S_i-\frac{tot}n)^2}n}=\sqrt{\frac{\sum_{i=1}^n(nS_i-tot)^2}{n^3}} \]也就是說我們只需要最小化\(\sum_{i=1}^n(nS_i-tot)^2\)即可。
我們設\(f_{x1,y1,x2,y2,k}\)表示把左上角為\((x1,y1)\),右下角為\((x2,y2)\)的矩陣劃分\(k\)次,所得的\(\sum(nS_i-tot)^2\)的最小值。
轉移過程就是列舉按哪一行/哪一列劃分,同時列舉如何把剩下\(k-1\)次劃分分給這兩部分。
這種資料範圍隨便跑。。。
程式碼:\(O(n^7)\)
#include<bits/stdc++.h> #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> #define Reg register #define RI Reg int #define Con const #define CI Con int& #define I inline #define W while #define N 10 #define LL long long using namespace std; int a,b,n,tot,s[N+5][N+5];LL f[N+5][N+5][N+5][N+5][N+5]; I LL DP(CI x1,CI y1,CI x2,CI y2,CI k)//DP,寫成記憶化搜尋的形式 { if(~f[x1][y1][x2][y2][k]) return f[x1][y1][x2][y2][k];RI i,j;LL t=1e18;//記憶化 if(!k) {for(t=0,i=x1;i<=x2;++i) for(j=y1;j<=y2;++j) t+=s[i][j];t=1LL*(n*t-tot)*(n*t-tot);goto End;}//k=0 for(i=x1;i^x2;++i) for(j=0;j^k;++j) t=min(t,DP(x1,y1,i,y2,j)+DP(i+1,y1,x2,y2,k-1-j));//按某一行分 for(i=y1;i^y2;++i) for(j=0;j^k;++j) t=min(t,DP(x1,y1,x2,i,j)+DP(x1,i+1,x2,y2,k-1-j));//按某一列分 End:return f[x1][y1][x2][y2][k]=t;//記憶化 } int main() { RI i,j;for(scanf("%d%d%d",&a,&b,&n),i=1;i<=a;++i) for(j=1;j<=b;++j) scanf("%d",s[i]+j),tot+=s[i][j];//統計序列總和 return memset(f,-1,sizeof(f)),printf("%.2lf\n",sqrt(1.0*DP(1,1,a,b,n-1)/n/n/n)),0;//注意計算最終答案 }