【u011】乘法难题

来源:互联网 发布:药物合成工艺优化 编辑:程序博客网 时间:2024/06/11 09:33

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

乘法难题是一种用一行的卡片来玩的单人游戏,每张卡片上有一个正整数。在游戏者从中拿出一卡片,并且得到一个分数,它等于被拿走的卡片上的数与这张卡片左右两张卡片上的整数的积。第一张与与最后一张卡片不能被拿出。在最后一次移动后,这行卡片中只剩下两张。 你的目标是怎样确定拿卡片的顺序,以使得总分数的值最小。例如,有一行的卡片,它上面的数字为10 1 50 20 5, 游戏者可以先取走1这张卡片,然后是20 和50,总分数为10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000,如果他先拿50, 然接着20,最后取出1, 总分数为1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150。


【输入格式】

输入文件的第一行包含卡片的总数N(3 <= N <= 100),第二行包含N个范围在1到100之间的整数(两个整数之间有一个空格)

【输出格式】

输出文件包含一个整数,为最少的分数。

【数据规模】

Sample Input1

610 1 50 50 20 5

Sample Output1

3650
【题解】
设f[i][j]表示从i到j,除了i和j之外都被取走所能得到的最小分数。
f[i][j] = min(f[i][k]+f[k][j]+a[i]*a[k]*a[j]); i<k<j;
初值:f[i][i+1] == 0;
更新方式如下:
for (int L=2;L<= n;L++)
for (int s = 1;s <= n-l;s++)
{
int t = s+l;
for (int k = s+1;k<=t-1;k++)
f[i][j] = min(f[s][k]+f[k][t]+a[i]*a[k]*a[t],f[i][j]);
}
最后答案为f[1][n];
这里一定要先枚举这段的长度。
这样我们可以先获得像f[1][3],f[2][4],f[3][5]..f[n-2][n]这样的值。
然后我们在求f[1][4]的时候k在2..3枚举
f[1][4] = min(f[1][2]+f[2][4]+a[1]*a[2]*a[4],f[1][3]+f[3][4]+a[1]*a[3]*a[4]);
可以看到我们在求f[1][4]的时候要用到的f[2][4],f[1][3]都已经求出来了 。
这是原因所在。
也是这种类型动规的原理->不断利用小的区间扩大区间。
【代码】
#include <cstdio>#include <cstring>int a[101],n,f[101][101];int main(){memset(f, 127 / 3, sizeof(f));//一开始f数组赋值为一个很大的数字。scanf("%d", &n);for (int i = 1; i <= n; i++)//读入数据scanf("%d", &a[i]);for (int i = 1; i <= n - 1; i++)//从i到i+1除了i和i+1都不拿 那就是什么都没有。f[i][i + 1] = 0;for (int l = 2;l <= n;l++)//先枚举小的长度。为后面大的长度作铺垫。for (int s = 1; s <= n - l; s++)//枚举起点。{int t = s + l;//这是终点for (int k = s + 1; k <= t - 1; k++)//利用之前得到的小的区间最优值扩大。{int temp = f[s][k] + f[k][t] + a[s] * a[t] * a[k];//f[s][k]里有s,k。f[k][t]也有k,t。//且只剩下k没取。那就把它取下来。看看是否更优。if (temp < f[s][t])f[s][t] = temp;}}printf("%d\n", f[1][n]);return 0;}


0 0
原创粉丝点击