线性最佳分割算法
题目描述:
给出任意一个一维数组,数组中又m个数,在不改变数顺序的前提下,将数分割成尽量相等的k份。
动态规划
动态规划方程式:f[i,j]=min(max(f[x,j-1],p[i]-p[x]));即i个数分成j份,他们的最佳分割值的大小是分成j-1份之中所有最佳
可能性得值和后继所有元素之和的最大值中的最小值。
为什么呢?
第一步,我们简单的看一个数组分成两份的情况。
把一个数组a[10]平均分成两份假设元素分别是1,2,3,4,5
则算法如此运行:
1| 2 3 4 5 maxvalue:14.
1 2| 3 4 5 maxvalue:12
1 2 3| 4 5 maxvalue:9
1 2 3 4| 5 maxvalue:10
因此最佳分割是1 2 3和4 5
第二步,我们假设数组分成三份
1 2 3 4 5
按照算法就会遍历x个元素分成2组所有的最佳情况,和后续元素组成3组
数组 分割点 组1 2 3 max
1 1 0 1 14 14
1 2 2 1 2 12 12
1 2 3 3 3 3 9 9
1 2 3 4 4 6 4 5 6
1 2 3 4 5 5 6 9 0 9
取最大值的最小值
于是分成三组的最佳分割就是 1 2 3| 4| 5
任意多个元素的情况下,只要记录下x个元素的j-1分割所有最佳情况,就可以计算出i个元素分成j组的最佳情况。
算法设计:
使用m[i][j]记录所有状态:i个元素分成j组的最佳分割值(每组元素之和的最大值)
初始化:
m[i][1]表示了a[1]~a[i]元素的前缀和i个元素分成1组就是本身
m[1][i]表示 a[i]
计算m[i][j] 就必须先求出m[x][j-1]和p[i]-p[x]的所有最大值中的最小值
于是如此地推下去
d[i][j]记录下当i个元素分成j份的时候分割的地方在哪里,也就是数组下标。
1 #include <stdio.h> 2 #define INF 1000000000 3 int a[100],p[100]; 4 int m[100][100]; 5 int d[100][100]; 6 int n,k; 7 int max(int p1,int p2) 8 { 9 return p1<p2?p2:p1; 10 } 11 void partition() 12 { 13 //计算出前缀和 填充 矩阵m 14 int i,j,x; 15 p[0]=0; 16 for(i=1;i<=n;i++) 17 { 18 p[i]=p[i-1]+a[i]; 19 } 20 for(i=0;i<=n;i++)for(j=0;j<=n;j++)d[i][j]=-1; 21 for(i=1;i<=n;i++)m[i][1]=p[i]; 22 for(i=1;i<=n;i++)m[1][i]=a[i]; 23 for(i=2;i<=n;i++) 24 { 25 for(j=2;j<=k;j++) 26 { 27 m[i][j]=INF; 28 for(x=1;x<=i-1;x++)//在i-1个元素中寻找分割点 29 { 30 if(x<j)continue; 31 int s=max(m[x][j-1],p[i]-p[x]);//寻找分成可能包含余下全部元素 32 if(m[i][j]>s) 33 { 34 m[i][j]=s;//x个元素 分成 j份的最大值=i个元素分成j-1份的最大值 或者是余下的数组成的最大值 35 d[i][j]=x;// 36 } 37 } 38 } 39 } 40 printf("Here is the m matrix:\n"); 41 for(i=0;i<=n;i++) 42 { 43 for(j=0;j<=n;j++) 44 { 45 printf("%d ",m[i][j]); 46 } 47 printf("\n"); 48 } 49 50 printf("Here is the d matrix:\n"); 51 for(i=0;i<=n;i++) 52 { 53 for(j=0;j<=n;j++) 54 { 55 printf("%d ",d[i][j]); 56 } 57 printf("\n"); 58 } 59 } 60 int main(int argc, const char * argv[]) 61 { 62 63 // insert code here... 64 int i; 65 scanf("%d",&n); 66 scanf("%d",&k); 67 a[0]=0; 68 for(i=1;i<=n;i++) 69 { 70 scanf("%d",&a[i]); 71 } 72 partition(); 73 return 0; 74 }