[08山东省选]2298 石子合并 即POJ 1738 An old Stone Game
在一个操场上摆放着一排N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将N堆石子合并成一堆的最小得分。
第一行是一个数N。
以下N行每行一个数A,表示石子数目。
共一个数,即N堆石子合并成一堆的最小得分。
4
1
1
1
1
8
对于 30% 的数据,1≤N≤100
对于 60% 的数据,1≤N≤1000
对于 100% 的数据,1≤N≤40000
对于 100% 的数据,1≤A≤200
分类标签 Tags 点此展开
题意: 石子合并问题, 将相邻两堆石子合并, 每次得分是合并成新的一堆石子个数, 最后累加最小值.
解题思路:
1. 这类题目一开始想到是DP, 设dp[i][j]表示第i堆石子到第j堆石子合并最小得分.
状态方程: dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
sum[i]表示第1到第i堆石子总和. 递归记忆化搜索即可.
2. 不过此题有些不一样, 1<=n<=50000范围特大, dp[50000][50000]开不到这么大数组.
问题分析:
(1). 假设我们只对3堆石子a,b,c进行比较, 先合并哪2堆, 使得得分最小.
score1 = (a+b) + ( (a+b)+c )
score2 = (b+c) + ( (b+c)+a )
再次加上score1 <= score2, 化简得: a <= c, 可以得出只要a和c的关系确定,
合并的顺序也确定.
(2). GarsiaWachs算法, 就是基于(1)的结论实现.找出序列中满足stone[i-1] <=
stone[i+1]最小的i, 合并temp = stone[i]+stone[i-1], 接着往前面找是否
有满足stone[j] > temp, 把temp值插入stone[j]的后面(数组的右边). 循环
这个过程一直到只剩下一堆石子结束.
(3). 为什么要将temp插入stone[j]的后面, 可以理解为(1)的情况
从stone[j+1]到stone[i-2]看成一个整体 stone[mid],现在stone[j],
stone[mid], temp(stone[i-1]+stone[i-1]), 情况因为temp < stone[j],
因此不管怎样都是stone[mid]和temp先合并, 所以讲temp值插入stone[j]
的后面是不影响结果.
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
#define N 50010
int t=,n,a[N];
ll ans=;
void work(int k){
int tmp=a[k-]+a[k];
ans+=tmp;
for(int i=k;i<t-;i++)
a[i]=a[i+];
t--;
int j=;
for(j=k-;j>&&a[j-]<tmp;j--)
a[j]=a[j-];
a[j]=tmp;
while(j>=&&a[j]>=a[j-]){
int d=t-j;
work(j-);
j=t-d;
}
}
int main(){
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%d",&a[i]);
for(int i=;i<n;i++){
a[t++]=a[i];
while(t>=&&a[t-]<=a[t-])
work(t-);
}
while(t>)
work(t-);
printf("%lld\n",ans);
return ;
}
-----------------------------------------------------------------------------------------------------------------------------------------------
华丽的分割线
------------------------------------------------------------------------------------------------------------------------------------------------
以下是石子合并系列问题的常用思路,现附上。(以下大部分来自网络,代码未经测试,看看思路就好)
石子合并问题是最经典的DP问题。首先它有如下3种题型:
(1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。
分析:当然这种情况是最简单的情况,合并的是任意两堆,直接贪心即可,每次选择最小的两堆合并。本问题实际上就是哈夫曼的变形。
(2)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。
直线取石子问题的平行四边形优化:
#include <iostream>
#include <string.h>
#include <stdio.h> using namespace std;
const int INF = << ;
const int N = ; int dp[N][N];
int p[N][N];
int sum[N];
int n; int getMinval()
{
for(int i=; i<=n; i++)
{
dp[i][i] = ;
p[i][i] = i;
}
for(int len=; len<n; len++)
{
for(int i=; i+len<=n; i++)
{
int end = i+len;
int tmp = INF;
int k = ;
for(int j=p[i][end-]; j<=p[i+][end]; j++)
{
if(dp[i][j] + dp[j+][end] + sum[end] - sum[i-] < tmp)
{
tmp = dp[i][j] + dp[j+][end] + sum[end] - sum[i-];
k = j;
}
}
dp[i][end] = tmp;
p[i][end] = k;
}
}
return dp[][n];
} int main()
{
while(scanf("%d",&n)!=EOF)
{
sum[] = ;
for(int i=; i<=n; i++)
{
int val;
scanf("%d",&val);
sum[i] = sum[i-] + val;
}
printf("%d\n",getMinval());
}
return ;
}
#include <iostream>
#include <string.h>
#include <stdio.h> using namespace std;
const int INF = << ;
const int N = ; int mins[N][N];
int maxs[N][N];
int sum[N],a[N];
int minval,maxval;
int n; int getsum(int i,int j)
{
if(i+j >= n) return getsum(i,n-i-) + getsum(,(i+j)%n);
else return sum[i+j] - (i> ? sum[i-]:);
} void Work(int a[],int n)
{
for(int i=;i<n;i++)
mins[i][] = maxs[i][] = ;
for(int j=;j<n;j++)
{
for(int i=;i<n;i++)
{
mins[i][j] = INF;
maxs[i][j] = ;
for(int k=;k<j;k++)
{
mins[i][j] = min(mins[i][j],mins[i][k] + mins[(i+k+)%n][j-k-] + getsum(i,j));
maxs[i][j] = max(maxs[i][j],maxs[i][k] + maxs[(i+k+)%n][j-k-] + getsum(i,j));
}
}
}
minval = mins[][n-];
maxval = maxs[][n-];
for(int i=;i<n;i++)
{
minval = min(minval,mins[i][n-]);
maxval = max(maxval,maxs[i][n-]);
}
} int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=;i<n;i++)
scanf("%d",&a[i]);
sum[] = a[];
for(int i=;i<n;i++)
sum[i] = sum[i-] + a[i];
Work(a,n);
printf("%d %d\n",minval,maxval);
}
return ;
}
[08山东省选]2298 石子合并 即POJ 1738 An old Stone Game的更多相关文章
- 题解报告:poj 1738 An old Stone Game(区间dp)
Description There is an old stone game.At the beginning of the game the player picks n(1<=n<=5 ...
- POJ 1738 An old Stone Game(石子合并 经典)
An old Stone Game Time Limit: 5000MS Memory Limit: 30000K Total Submissions: 3672 Accepted: 1035 ...
- POJ 1738 石子合并2 GarsiaWachs算法
石子合并(GarsiaWachs算法) 只能用该算法过!!! 详解看代码 //#pragma comment(linker, "/STACK:167772160")//手动扩栈~~ ...
- ny737 石子合并(一) 总结合并石子问题
描述: 在一个圆形操场的四周摆放着n 堆石子.现要将石子有次序地合并成一堆. 规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将n堆石子合并 ...
- 【BZOJ 3229】 3229: [Sdoi2008]石子合并 (GarsiaWachs算法)
3229: [Sdoi2008]石子合并 Description 在一个操场上摆放着一排N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合 ...
- RQNOJ 490 环形石子合并
题目链接:https://www.rqnoj.cn/problem/490 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一 ...
- 石子合并[DP-N3]
题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...
- 51Nod 1021 石子合并 Label:Water DP
N堆石子摆成一条线.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价.计算将N堆石子合并成一堆的最小代价. 例如: 1 2 3 4,有 ...
- BZOJ 3229: [Sdoi2008]石子合并
3229: [Sdoi2008]石子合并 时间限制: 3 Sec 内存限制: 128 MB提交: 497 解决: 240[提交][][] 题目描述 在一个操场上摆放着一排N堆石子.现要将石子有次序 ...
随机推荐
- django 删除表后如何恢复
大家都知道Python manage.py makemigrations 创建迁移文件也就是sql语句,python manage.py migrate执行makemigrations创建的文件,如果 ...
- asp.net限制用户登录错误次数
很经常在登录一个网站的时候看到,如果你登录的时候输入的账号密码错误超过三次就被锁定,然后等一段时间才能继续登录,最最经常使用的就是银行系统啦~~ 该功能处理流程如下: string uid = Req ...
- 初识Nginx及编译安装Nginx
初识Nginx及编译安装Nginx 环境说明: 系统版本 CentOS 6.9 x86_64 软件版本 nginx-1.12.2 1.什么是Nginx? 如果你听说或使用过Apache软件 ...
- 2017.3.31 spring mvc教程(七)多视图控制器
学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...
- HNU11376:Golf Bot
Problem description Input The first line has one integer: N, the number of different distances the G ...
- google兴趣点下载工具
继上次百度兴趣点版本的发布以后,发现百度只能下载本国数据,并且数据完整度还是和google的少一些,所以本次经过钻研与解密,实现了google地图下载工具,版本的主要功能如下: 1.支持多线程下载,支 ...
- @property和@x.setter和@x.deleter表示可读可写可删除
@property可以将python定义的函数“当做”属性访问,从而提供更加友好访问方式,但是有时候setter/deleter也是需要的.1>只有@property表示只读.2>同时有@ ...
- Url Scheme实现APP间通信、分享
代码地址如下:http://www.demodashi.com/demo/12748.html 简介: URL Scheme就是一个可以让app相互之间可以跳转的对外接口.通过给APP定义一个唯一的U ...
- BIOS截图中文
- 使Gallery时设置居左显示
Gallery中的图片默认是居中显示的.可是在非常多情况下我们须要它居左显示,这样做有一个简单方法.就是把Gallery的left设置为负多少,如以下的方法: Drawable drawable=ca ...