男人不易八题之POJ 1738 AN OLD STONE GAME解题报告

原题目传送门: http://poj.org/problem?id=1738
题目大意是有n堆石子放成一行,石子堆有各自的重量。要求把这些石子合并为一堆,规则为合并相邻的两堆石子,得分为合并后的石子堆重量,且得分累加。现求最小总得分。
很容易想到一种区间型dp的思路,可惜n的范围有点大, n<=50000
所以就发现了一种新的算法——GarsiaWachs算法。
大概意思就是在石子堆a1,a2,…,an中,每次找到最小的k满足a[k-1]<=a[k+1],合并a[k-1]和a[k],并把合并后的石子堆插入到ak之前,离ak最近,且满足a[j]>a[k-1]+a[k]的石子堆aj之后。重复以上过程,知道合并结束。


可见算法复杂度为O(n^2),加之题目给了诸多条件来限制常数因子,导致朴素的GarsiaWachs可以在题目5s的时间限制内跑完。听说有一种平衡树优化的算法,蒟蒻暂时还没想出来怎么实现。算法的正确性和具体效率分析在下面博客中有。
http://fanhq666.blog.163.com/blog/static/81943426201062865551410/


对了,提醒一点,如果n=1不要输出重量,直接输出0!!!!!

#include
#include
#include
#include
using namespace std;
const int MAXN=55555,INF=1<<30;
struct ARC{
	int last,next,data;
	void init(){
		next=last=0;
		data=INF;
	}
}arc[MAXN];
void in(int &cnt)
{
	arc[cnt].next=cnt+1;
	arc[cnt+1].last=cnt;
	scanf("%d",&arc[++cnt].data);
}
void del(int u)
{
	arc[arc[u].last].next=arc[u].next;
	arc[arc[arc[u].last].next].last=arc[u].last;
}
void reinsert(int x,int u)
{
	for(int i=arc[u].last;;i=arc[i].last) if(arc[i].data>x)
	{
		arc[u].last=i;
		arc[u].data=x;
		arc[u].next=arc[i].next;
		arc[arc[u].next].last=u;
		arc[i].next=u;
		return;
	}
}
void work(int n)
{
	int ans=0,cnt=0;
	for(int i=0;i<=n+1;i++) arc[i].init();
	for(int i=1;i<=n;i++) in(cnt);
	for(int i=1;i


你可能感兴趣的:(男人不易八题之POJ 1738 AN OLD STONE GAME解题报告)