|
板凳
楼主 |
发表于 2017-10-3 15:13:42
|
只看该作者
- DP的做法是典型的的背包问题变形,若设f[i][j]为前面i本书分成j个人抄时的最少时间,s[i][j]为一个抄第i到第j本书的时间,则转移方程“
- f[i][1]=s[1][i]
- f[i][j]=min(f[i-k][j-1]+s[i-k+1][i])
- 看得出这个转移方程和背包问题很相似,套用那个程序的框架即可。
- // 1 3 7 8 9 2 4 5 6九个数字按顺序分成三堆,使最大的那一堆最小
- #include <iostream>
- #include <iomanip>
- using namespace std;
- int a[10]= {0,1,2,3,4,5,6,7,8,9}; //十堆原始数据
- int s[10][10]; //s[i][j]表示第i堆到第j堆共有多少个 DP初始状态 不划分的情况
- int f[10][4]; //f[i][j]前i个石头被分成j堆得最小值 DP状态
- int w[10][4]; //划分点,决策方法
- int i,j,k,t1,t2,t,m,p;
- int main()
- {
- for (i=1; i<=9; i++)
- {
- s[i][i]=a[i];
- for (j=i+1; j<=9; j++) s[i][j]=s[i][j-1]+a[j];
- }
- //输出检查下
- cout<<"================s====\n";
- for (i=1; i<=9; i++)
- {
- for (j=1; j<=9; j++) cout<<setw(4)<<s[i][j];
- cout<<endl;
- }
- //初始状态 不划分的话就是直接加
- for (i=1; i<=9; i++) f[i][1]=s[1][i];
- for (j=2; j<=3; j++) //分成2堆开始 注意枚举顺序
- for (i=j; i<=9; i++) //i显然要大于j
- {
- m=9999; //最小值初值
- for (k=j-1; k<=i-1; k++) //枚举划分点 注意取值范围!!!
- {
- t1=f[k][j-1]; //前面一段 k个数字分成j-1份
- t2=s[k+1][i]; //后面一段 自成一段
- if (t1>t2) t=t1;
- else t=t2;//取最大值
- if (t<m) m=t,p=k; //记录最小值和位置
- }
- f[i][j]=m,w[i][j]=p; //DP更新值
- }
- //检查f数组
- cout<<"================f====\n";
- for (j=1; j<=3; j++)
- {
- for (i=1; i<=9; i++) cout<<setw(4)<<f[i][j];
- cout<<endl;
- }
- cout<<f[9][3]<<endl;
- cout<<"================w====\n";
- for (j=1; j<=3; j++)
- {
- for (i=1; i<=9; i++) cout<<setw(4)<<w[i][j];
- cout<<endl;
- }
- cout<<f[9][3]<<endl;
- }
复制代码 |
|