石子合并,Multiplication Puzzle(区间dp)

在一个操场上摆放着一排 N 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。

试设计一个算法,计算出将 N 堆石子合并成一堆的最小得分。

输入格式
第一行一个整数 N。

接下来 N 行,第 i 行一个整数 ai代表第 i堆石子的石子数。

输出格式
输出将所有石子合并为一堆的最小得分。
输入
4
1
1
1
1
输出
8
它的一道简单题(但实际上在洛谷里N(N>=40000)的数据很大,能过的样例很少,具体如何改请看GarsiaWachs的一些知识)

#include <bits/stdc++.h>
using namespace std;
const int nn=110;
int n,a[nn],b[nn],c[nn][nn]; 
int main(){
	memset(c,0x3f,sizeof(c));
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
		b[i]=b[i-1]+a[i];
		c[i][i]=0;
	}
	for(int len=2;len<=n;len++){//区间长度 
		for(int l=1;l+len-1<=n;l++){//区间起点 
			int r=l+len-1;//区间终点 
			for(int i=l;i<r;i++)//区间的分割点找最小值 
			c[l][r]=min(c[l][r],c[l][i]+c[i+1][r]+b[r]-b[l-1]);
		}
	}
	cout<<c[1][n];
    return 0;
}


The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.

The goal is to take cards in such order as to minimize the total number of scored points.

For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000

If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.
Input
The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.
Output
Output must contain a single integer - the minimal score.
Sample Input
6
10 1 50 50 20 5
Sample Output
3650

大致翻译:

乘法拼图是用一排牌来玩的,每一张牌都包含一个正整数。在移动过程中,玩家从这一行中取出一张牌,并按所取牌上的数字与左右两张牌上的数字的乘积来得分。不允许取出第一张和最后一张卡片。最后一招结束后,这一排只剩下两张牌。

我们的目标是采取这样的顺序卡,以尽量减少总得分。

例如,如果一行中的牌包含数字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.

这题本质上和上面那题差不多,但是一定要注意边界条件!!!

//#include <bits/stdc++.h>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int nn=110;
#define inf 0x3f3f3f3f
ll n,a[nn],c[nn][nn]; 
int main(){
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lld",a+i);
	}
	for(ll len=2;len<n;len++){//区间长度 
		for(ll l=2;l+len-1<=n;l++){//区间起点 ,由于l-1的操作所以从2开始
			ll r=l+len-1;//区间终点 
			c[l][r]=inf;//找最小就需要初始化成最大
			for(ll i=l;i<r;i++)//区间的分割点找最小值 
			c[l][r]=min(c[l][r],c[l][i]+c[i+1][r]+a[l-1]*a[i]*a[r]);
		}
	}
	cout<<c[2][n];
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值