小白笔记------------------最小m段和问题

来源:互联网 发布:哈工大人工智能产业园 编辑:程序博客网 时间:2024/05/18 03:15
最近在看动态规划法,对状态转移方程总是写不出来例如今天这个问题:
这个问题怎么才能抽象出状态转移方程呢?
我们考虑将5个数分成3段的情形,首先考虑分成1段的时候,一个数只能分成1个段,则f[1][1] = a[1],如果是两个数呢,两个数可以分成1段则,f[2][1] = a[1] + a[2],由此易得对于i个数,f[i][1] = a[1] + a[2] + ...+a[i]。接着考虑分成2段的时候,对于一个数无法分成两段,则f[1][2] = 0,如果是两个数,则易知,f[2][1] = a[1],f[2][2] = a[2],或者是另外一种情况只有两种可能,看到这里也许还不太明显,如果是三个数,分成两段,则必定有一个段数是分成一段,一个数单独一段,如果是四个数,同样的,则必定有一段数分成一段,一段或者一个数分成一段,从这里就容易发现,不论怎么分,它总是一个在剩下数中分成1段和j-1段的过程,而我们需要做的就是将这个抽象成状态转移方程,到这里应该可以了。

f[i][j] = min(max(f[i][1]-f[k][1],f[k][j-1]));这是最小m段和的状态方程,f[i][j]表示i个数分成j个子段的最小最大字段和,式子表示的意思是前k个数分成j-i个段,后k个数分成一段,因为k是循环的则能取到i个数分成j段的最大和,然后再从最大和中取最小值。

用c写的小测试
/******************************************************* Author       : Aaron92* Date   : 2016-06-07 20:37* Filename     : minestm.c* Description  : ******************************************************/#include<stdio.h>#include<string.h>#define n 5int m = 2;int a[n] = {1,2,3,4,5};int f[n][n] ;int solve(int m){memset(f,0,sizeof(f));int i ,j,s,k;f[0][1] = a[0];for(i = 1;i < n;i++){f[i][1] = f[i-1][1] + a[i];}int maxt,tmp;for(s = 2;s <= m;s++){for(j = s;j < n;j++){tmp = 1e9;for(k = s-1;k < j;k++){if((f[j][1]-f[k][1]) >= f[k][s-1]){maxt = f[j][1]-f[k][1];}else{maxt = f[k][s-1];}if(tmp > maxt){tmp = maxt;}}f[j][s] = tmp;}}return f[n-1][m];}int main(int argc,char ** argv){int result = solve(m);printf("%d\n",result);return 0;}


0 0
原创粉丝点击