日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

不止代码:ybtoj-棋盘分割(二维区间dp)

發布時間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不止代码:ybtoj-棋盘分割(二维区间dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

將一個8*8的棋盤進行如下分割:將原棋盤割下一塊矩形棋盤并使剩下部分也是矩形,再將剩下的部分繼續如此分割,這樣割了n-1次后,連同最后剩下的矩形棋盤共有n塊矩形棋盤。 (每次切割都只能沿著棋盤格子的邊進行)

原棋盤上每一格有一個分值,一塊矩形棋盤的總分為其所含各格分值之和。現在需要把棋盤按上述規則分割成n塊矩形棋盤,并使各矩形棋盤總分的均方差最小。求出均方差的最小值。
其中,均方差的定義為:

(里面的括號應該還有一個平方,不然固輸0豈不美哉)

數據范圍

1<n<15,所有數均為不大于100的非負整數

解析

分析題面可以發現一些結論:
1.只要大矩陣與n確定,平均值就是可以算出的定值
2.每次分完后只能對其中的一部分繼續切割
對于第2條舉個例子:n=4時,田字型的切割就是不合法的,這對于本題至關重要
我們可以先算出均方差根號里面那個西格瑪加和的總值的最小值,最后再除n開根號
定義dp[x1][y1][x2][y2][k]:左上角為x1,y1,右下角為x2,y2還可以切k刀時,切成的k+1部分西格瑪方差的最小值
顯然,k=0時:

if(k==0) return abs((double)he(x1,y1,x2,y2)-ave)*abs((double)he(x1,y1,x2,y2)-ave);

ave為提前可算好的平均值,he函數可以用二維前綴和O(1)求出,具體見代碼(其實遍歷求本題時間可能也爆不了。。。 )
對于轉移,我們枚舉切出去的那個不能再切的矩形的位置即可

代碼

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <queue> #include <string> #include<map> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)); #define ull unsigned ll using namespace std; const int N=15; int m,n,tot; int mp[10][10],sum[10][10]; double ave; double dp[N][N][N][N][N]; int he(int x1,int y1,int x2,int y2){return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]; } double find(int x1,int y1,int x2,int y2,int k){if(dp[x1][y1][x2][y2][k]) return dp[x1][y1][x2][y2][k];if(k==0) return abs((double)he(x1,y1,x2,y2)-ave)*abs((double)he(x1,y1,x2,y2)-ave);dp[x1][y1][x2][y2][k]=1e9;for(int i=x1;i<x2;i++){//橫著切 dp[x1][y1][x2][y2][k]=min(dp[x1][y1][x2][y2][k],find(x1,y1,i,y2,0)+find(i+1,y1,x2,y2,k-1));dp[x1][y1][x2][y2][k]=min(dp[x1][y1][x2][y2][k],find(x1,y1,i,y2,k-1)+find(i+1,y1,x2,y2,0));//注意這里還要反著枚舉一遍,因為不能切的部分可能在下邊 }for(int j=y1;j<y2;j++){//豎著切 dp[x1][y1][x2][y2][k]=min(dp[x1][y1][x2][y2][k],find(x1,y1,x2,j,0)+find(x1,j+1,x2,y2,k-1));dp[x1][y1][x2][y2][k]=min(dp[x1][y1][x2][y2][k],find(x1,y1,x2,j,k-1)+find(x1,j+1,x2,y2,0));}return dp[x1][y1][x2][y2][k]; } int main(){scanf("%d",&n);for(int i=1;i<=8;i++){for(int j=1;j<=8;j++) scanf("%d",&mp[i][j]);}for(int i=1;i<=8;i++){for(int j=1;j<=8;j++) sum[i][j]=sum[i][j-1]+mp[i][j];}for(int j=1;j<=8;j++){for(int i=1;i<=8;i++) sum[i][j]+=sum[i-1][j];}ave=1.0*sum[8][8]/n;printf("%.3lf",sqrt(1.0*find(1,1,8,8,n-1)/n)); } /* 樣例: 3 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 3ans:1.633 */

心得

一次AC萬歲!!!!

這道dp做的還是不錯的,尤其是很快發現了解析中提到的兩條關鍵結論,從而帶出了思路
所以要仔細審題!!
dp就像數學平幾,有時候思路一下子通了就不難了awa

thanks for reading!

總結

以上是生活随笔為你收集整理的不止代码:ybtoj-棋盘分割(二维区间dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。