题意:给你一堆数,让你组成m个集合,集合的价值是集合内元素的最大值与最小值的差的平方,求m个集合的价值总和最小
思路:
先给出TLE代码,斜率优化下次给出,转移方程dp[i][j]=min(dp[i][j],dp[i-1][k]+(a[j]-a[k+1])*(a[j]-a[k+1]));(ps:tzw竟然说买包烟十个人,九个人都会斜率优化过题,emmm)
#include <bits/stdc++.h> using namespace std; const int maxn=10005; const int inf=0x3f3f3f3f; int a[maxn],dp[maxn][maxn]; int que[maxn]; int n,m; int main() { int T; scanf("%d",&T); int cas=1; while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } sort(a+1,a+1+n); for(int i=0;i<=m;i++){ for(int j=0;j<=n;j++){ if(j==0)dp[i][j]=0; else dp[i][j]=inf; } } for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ for(int k=0;k<j;k++){ dp[i][j]=min(dp[i][j],dp[i-1][k]+(a[j]-a[k+1])*(a[j]-a[k+1])); // printf("test %d dp[%d][%d] == %d ",k,i,j,dp[i][j]); } } } // for(int i=0;i<=m;i++){ // for(int j=0;j<=n;j++){ // printf("%d ",dp[i][j]); // } // puts(""); // } printf("Case %d: %d ",cas++,dp[m][n]); } return 0; }
已补,代码参照http://blog.sina.com.cn/s/blog_6e63f59e0101aeaf.html
不知道为什么对于二维的斜率优化,写成相除的形式就跑不出样例,感觉在vj上交的没有什么错,只用了slop函数,没有什么其他特别的地方
-----手动分割------------
这里是四边形不等式优化,最近才对四边形不等式有所突破
主要得益于赵爽的《动态规划加速原理 之四边形不等式》
窝觉得论文写得还是很容易懂的,只要能认真看,以及手动进行数学证明,结合网上的题解,对于四边形不等式的优化的理解应该是没什么问题的
最近几天把黑书补一下
然后尽量多刷一下四边形优化的题,斜率优化已经懂了许多了
附上四边形代码(说实话,我不是很懂初始化,可能需要手动推算一下,还是懒):
#include <bits/stdc++.h> using namespace std; const int maxn=100007; const int inf=0x3f3f3f3f; int n,m,ans,T; int a[10005],dp[5005][10005],s[5005][10005]; int main() { scanf("%d",&T); int cas=1; while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } sort(a+1,a+1+n); memset(dp,0x3f,sizeof(dp)); for(int i=0;i<=m;i++){ dp[i][i]=0; s[i][i]=i; } for(int i=m+1;i<=n;i++){ s[m+1][i]=i; } for(int len=1;len<n;len++){ for(int i=1;i<=m;i++){ int j=len+i; if(j>n)break; for(int k=s[i][j-1];k<=s[i+1][j];k++){ int t=dp[i-1][k-1]+(a[k]-a[j])*(a[k]-a[j]); if(dp[i][j]>t){ dp[i][j]=t; s[i][j]=k; } } } } printf("Case %d: %d ",cas++,dp[m][n]); } return 0; }