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

来源:互联网 发布:mac的加速播放器 编辑:程序博客网 时间:2024/05/17 03:52
原题目传送门: 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<cstdio>#include<cstring>#include<climits>#include<algorithm>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<n;i++) for(int j=arc[0].next;j;j=arc[j].next){int l=arc[j].last,r=arc[j].next;if(arc[l].data<=arc[r].data){del(l);del(j); int weight=arc[l].data+arc[j].data;ans+=weight;reinsert(weight,j);break;}}printf("%d\n",ans);return;}int main(){int n;while(scanf("%d",&n)!=EOF&&n) work(n);}


3 0
原创粉丝点击