【Poj 1191 棋盤分割】題解
阿新 • • 發佈:2021-12-05
題目連結
題目
將一個8*8的棋盤進行如下分割:將原棋盤割下一塊矩形棋盤並使剩下部分也是矩形,再將剩下的部分繼續如此分割,這樣割了(n-1)次後,連同最後剩下的矩形棋盤共有n塊矩形棋盤。(每次切割都只能沿著棋盤格子的邊進行)原棋盤上每一格有一個分值,一塊矩形棋盤的總分為其所含各格分值之和。現在需要把棋盤按上述規則分割成n塊矩形棋盤,並使各矩形棋盤總分的均方差最小。
均方差,其中平均值,xi為第i塊矩形棋盤的總分。
請程式設計對給出的棋盤及n,求出O'的最小值。
思路
化簡式子可知原式是求:
\[\Large\sqrt{\frac{\sum_{i=1}^n x_i^2-\frac{(\sum_{i=1}^n x_i)^2}{n}}{n}} \]\(\frac{(\sum_{i=1}^n x_i)^2}{n}\)
設 \(dp(lx, ly, rx, ry, k)\) 表示在 \((lx, ly)\) 到 \((rx, ry)\) 的區間裡分成 \(k\) 塊每塊的平方和最小值。
轉移時可以考慮橫切豎切的情況。
為了方便統計答案,上面的式子 \(\sqrt{\frac{\sum_{i=1}^n x_i^2-\frac{(\sum_{i=1}^n x_i)^2}{n}}{n}}\) 可以化簡為:
\[\Large\sqrt{\frac{\sum_{i=1}^n x_i^2}{n}-(\frac{\sum_{i=1}^n x_i}{n})^2} \]用記憶化搜尋實現會更好。
Code
// Problem: 棋盤分割 // Contest: POJ - Noi 99 // URL: http://poj.org/problem?id=1191 // Memory Limit: 10 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // #include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; #define int long long inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+ (x<<3)+(ch^48);ch=getchar();}return x*f;} //#define M //#define mo #define N 10 int n, m, i, j, k; int f[N][N][N][N][16]; int s[N][N], a[N][N], sigam[N][N][N][N]; double he; int sum(int lx, int ly, int rx, int ry) { if(sigam[lx][ly][rx][ry]!=-1) return sigam[lx][ly][rx][ry]; int Sum=s[rx][ry]-s[lx-1][ry]-s[rx][ly-1]+s[lx-1][ly-1]; return sigam[lx][ly][rx][ry]=Sum*Sum; } int dfs(int lx, int ly, int rx, int ry, int k) { if(f[lx][ly][rx][ry][k]!=-1) return f[lx][ly][rx][ry][k]; if(k==1) return f[lx][ly][rx][ry][k]=sum(lx, ly, rx, ry); int ans=999999999999; for(int i=lx; i<rx; ++i) { ans=min(ans, dfs(lx, ly, i, ry, k-1)+sum(i+1, ly, rx, ry)); ans=min(ans, sum(lx, ly, i, ry)+dfs(i+1, ly, rx, ry, k-1)); } for(int i=ly; i<ry; ++i) { ans=min(ans, dfs(lx, ly, rx, i, k-1)+sum(lx, i+1, rx, ry)); ans=min(ans, sum(lx, ly, rx, i)+dfs(lx, i+1, rx, ry, k-1)); } return f[lx][ly][rx][ry][k]=ans; } signed main() { // freopen("tiaoshi.in", "r", stdin); // freopen("tiaoshi.out", "w", stdout); while(scanf("%lld", &k)!=EOF) { memset(f, -1, sizeof(f)); memset(sigam, -1, sizeof(sigam)); memset(s, 0, sizeof(s)); n=8; for(i=1; i<=n; ++i) for(j=1; j<=n; ++j) a[i][j]=read(); for(i=1; i<=n; ++i) for(j=1; j<=n; ++j) s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]; he=double(double(s[n][n])/double(k)); // printf("%lld %lld %lf\n", dfs(1, 1, n, n, k), s[n][n], he); printf("%.3f\n", sqrt(double(dfs(1, 1, n, n, k))/double(k)-he*he)); } return 0; }