题目大意:
乘法谜题是一种用卡片玩的游戏,卡片按照一定顺序排列成一排,每张卡片上都有一个整数(范围是[1, 100]),游戏中玩家需要不断从序列中抽取就卡片,一次只能抽取一张,每抽取一张就要累加一次积分,此次积分等于抽出卡片上的数字和该卡片左右相邻卡片上的数字的乘积(头尾两张卡片不能抽,也就是说抽到最后就为剩下头尾两张卡片),现要求最后的总积分要最小,最小者获胜。
现只有一个测例,测例中给出卡片的数量n(3 ≤ n ≤ 100),接下来从左至右给出每张卡片上的数字,要求输出最终的最小总积分。
注释代码:
/*
* Problem ID : POJ 1651 Multiplication Puzzle
* Author : Lirx.t.Una
* Language : C
* Run Time : 0 ms
* Run Memory : 160 KB
*/
#include <stdio.h>
//得分的无穷大
//大于 100 × 100 × 100 × ( 100 - 2 )
#define INF 98000001
//maximum number of cards
//卡片的最大数量
#define MAXCARDN 100
#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
int c[MAXCARDN];//card[i]表示第i张卡片的数值,下标从0开始
//dp[i][j]表示从第i号卡片到第j号卡片之间进行题目要求规则抽取
//所得到的最大分数
int dp[MAXCARDN][MAXCARDN];
int
main() {
int n;//卡片数量
int i, j, k;//计数变量
int g;//间隔
int tmp;//临时变量
scanf("%d", &n);
for ( i = 0; i < n; i++ )
scanf("%d", c + i);
//对于间隔为1的dp值由于是全局静态变量的缘故都初始化为0了
//表示间隔为1的区间无法抽取卡片(无中间卡片,区间端点的两张卡片式不能抽取的)
for ( g = 2; g < n; g++ )//从间隔为2开始扫描
for ( i = 0, j = i + g; j < n; i++, j++ ) {
//所有[i, j]间隔都是g
dp[i][j] = INF;//先初始化为无穷
for ( k = i + 1; k < j; k++ ) {//再[i, j]区间内逐个设置断点k
//抽取方法就是先抽完左半边再抽完右半边
//最后就只剩下i、j、k三张牌了
//下式就是转移方程了,不用担心间隔为1的区间,因为已经初始化为0了
tmp = dp[i][k] + dp[k][j] + c[i] * c[k] * c[j];
dp[i][j] = MIN( dp[i][j], tmp );
}
}
printf("%d\n", dp[0][n - 1]);
return 0;
}
无注释代码:
#include <stdio.h>
#define INF 98000001
#define MAXCARDN 100
#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
int c[MAXCARDN];
int dp[MAXCARDN][MAXCARDN];
int
main() {
int n;
int i, j, k;
int g;
int tmp;
scanf("%d", &n);
for ( i = 0; i < n; i++ )
scanf("%d", c + i);
for ( g = 2; g < n; g++ )
for ( i = 0, j = i + g; j < n; i++, j++ ) {
dp[i][j] = INF;
for ( k = i + 1; k < j; k++ ) {
tmp = dp[i][k] + dp[k][j] + c[i] * c[k] * c[j];
dp[i][j] = MIN( dp[i][j], tmp );
}
}
printf("%d\n", dp[0][n - 1]);
return 0;
}
单词解释:
puzzle:n, 谜题
product:n, 乘积