蓝桥杯 合并石子 GarsiaWachs算法

题意

中文题目,不解释

题解

从DP角度来看,这道题是非常有难度的。普通的DP就只能过90%的数据,貌似正解需要用到四边形优化。。。不过呢,有一位叫GarsiaWachs的大牛提出了一套算法,可以在O(N^2)的复杂度下解决这个问题。(原本的DP复杂度为O(N^3),据说使用平衡树优化以后可以达到O(NlogN),不过对于这道题没什么必要了)
网上关于GarsiaWachs算法有很多讲解,这里也简单讲一下。大致流程就是从序列中找出d[i]<=d[i+2]的那个位置,然后删除i和i+1位置上的元素。并且把他们的和放置到从i向前遍历第一个大于两数之和的元素之后。(网上有很多在这里没有讲清楚,这里重新阐述一下!)另外需要注意,如果遍历完前面所有元素都没有符合条件的元素,那么我们就将它们的和放置到链表的顶端。另外还需要注意,我们需要向链表最后加入一个值为INF的元素,以便于最后的合并处理(因为最后的合并处理也最少需要三个元素,用来保证d[i]<=d[i+2])

代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include<string.h>
#include<list>
#include<iostream>
#define LL long long
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(t) while(t)
#define MEM(a,b) memset(a,b,sizeof(a))
#define COUT(x) cout<<x<<endl
using namespace std;
long INF = 1e12;
list<int> a;

int main() {
    int n;
    W(~scanf("%d",&n)) {
        if(n==0)
            break;
        a.clear();
        for (int i = 0; i < n; i++) {
            int now;
            scanf("%d",&now);
            a.push_back(now);
        }
        a.push_back(INF);
        int now=n;
        int ans=0;
        for (int i = 0; i < n-1; i++) {
            list<int>::iterator it=a.begin();
            int m=0;
            list<int>::iterator stop;
            while(it!=a.end()) {
                list<int>::iterator aa=it;
                aa++,aa++;
                list<int>::iterator after=it;
                after++;
                if(*it<*aa) {
                    stop=aa;
                m=*it+*after;
                    ans+=m;
                    a.erase(it);
                    a.erase(after);
                    break;
                }
                it++;
            }
            it=stop;
            list<int>::iterator mx;
            bool has=false;
            if(stop!=a.begin()){
                it--;
                while(true) {
                    if(*it==INF){
                        if(it==a.begin()) break;
                        it--;
                      continue;
                    }
                    if(*it>m) {
                        it++;
                        a.insert(it,m);
                        has=true;
                        break;
                    }
                    if(it==a.begin()) break;
                    it--;
                }
            }
            if(!has) {
                a.push_front(m);
            }
        }
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/zhenlingcn/article/details/80269956