HDU 4960 Another OCD Patient(DP)

来源:互联网 发布:java的mvc框架 编辑:程序博客网 时间:2024/05/17 02:53

题意就是给你5000个数字,然后还有合并i个数字所需要的花费,然后每个数字只能合并1次,要把这串数字通过合并成为对称的数字,问你最小花费。

做法:用2个数组去分别保存从左往右以及从右往左对称的地方的长度,也就是比如1 3 4 3 1 2 2 ,b[0] = 2,b[1] = 1,c[0] = 1, c[1] = 2。

在预处理过后,数字就变得没有用了,有用的就是这2个数组,但是这里会出现一个情况就是中间某一段不能匹配成为相等的,也就是说必须要合并成1个数。

假设有k个匹配的段,dp[i]等于min{ 2个数组的 i 到 k 的数字全部合并一起的花费加上dp[k]}。这里推完后dp[k-1]加上前面说的中间那段不能匹配的花费就是解了。

等一下,这样并不对。因为可能最优解是中间那段加上左右2段匹配的合在一起再加上dp得到的。所以还需要推一遍,从中间开始推,ans = min{中间那段加上左右2段的数字个数合起来的花费加上dp[i]}。这点很容易想不到。

AC代码:

#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cstdlib>#include<stack>#include<cmath>#include<queue>#include<set>#include<ctime>#include<string.h>#include<string>using namespace std;#define ll __int64#define eps 1e-8ll a[5005];int cost[5005];int b[5005],c[5005];ll dp[5005];template<class T>inline void scan_d(T &ret) {      char c; ret=0;      while((c=getchar())<'0'||c>'9');      while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();  }  int main(){    #ifdef GLQ    freopen("input.txt","r",stdin);//    freopen("o.txt","w",stdout);    #endif // GLQ    int n,i,j;    while(~scanf("%d",&n)&&n)    {        for(i = 0; i < n; i++) scan_d(a[i]);        for(i = 1; i <= n; i++) scan_d(cost[i]);        i = 1;j = n-2;        int k = 0,nct1=1,nct2=1;        ll t1 = a[0], t2 = a[n-1];        int oldi=0,oldj=n-1,flag = 0;        while(1)        {            if(t1 > t2)            {                t2 += a[j--];                nct2++;            }            else if(t2 > t1)            {                t1 += a[i++];                nct1++;            }            else if(t2 == t1)            {                b[k] = nct1;                c[k++] = nct2;                nct1=nct2=1;                oldi = i;                oldj = j;                if(i==j+1) break;                t1=a[i++];                t2=a[j--];            }            if(j < i-1)            {                flag = 1;                break;            }        }        ll jia=0;        if(flag) jia = cost[oldj-oldi+1];        memset(dp,0,sizeof(dp));//        for(i = 0; i < k; i++) cout<<b[i]<<" "<<c[i]<<endl;        int temp1=0,temp2=0;        for(i = 0; i < k; i++)        {            dp[i] = (ll)cost[temp1+b[i]]+(ll)cost[temp2+c[i]];            temp1 = b[i]; temp2 = c[i];            for(j = i-1; j >= 0; j--)            {                dp[i] = min(dp[i],(ll)cost[temp1]+(ll)cost[temp2]+dp[j]);                temp1 += b[j]; temp2 += c[j];            }//            cout<<temp1<<" "<<temp2<<endl;//            cout<<dp[i]<<endl;        }        ll ans = min(dp[k-1]+(ll)jia,(ll)cost[n]);        if(k == 0)        {            printf("%d\n",cost[n]);            continue;        }        int w1 = 0,w2 = 0;        for(i = k-1; i >= 0; i--)        {            ans = min(ans,dp[i]+(ll)cost[oldj-oldi+1+w1+w2]);            w1 += b[i]; w2 += c[i];        }        printf("%I64d\n",ans);    }    return 0;}



0 0
原创粉丝点击