您的位置:首页 > 其它

沙子合并、石子合并、能量项链解题报告。

2017-10-08 19:27 253 查看
Task1 沙子合并:  设有N堆沙子排成一排,其编号为1,2,3,…,N(N< =300)。每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为  1    3    5    2  我们可以先合并1、2堆,代价为4,得到4  5  2  又合并  1,2堆,代价为9,得到9  2  ,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代价为7,得到4 
7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总的代价最小。输出最小代价。

   读完题首先想到最简单的暴力搜索,然而数据范围N<=300,这样做一定会TLE。于是我们想到用区间DP来做这道题。用sum【j】表示前j个数之和。

可得到状态转移方程:f【i】【j】=min(f【i】【l】+f【l】【j】+sum【j】-sum【i-1】,f【i】【j】)

Task2:石子合并

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分。

这道题与Task1的区别只有是放在了环形操场上,所以我们可以把环形问题“”完全“”转换成长度为2倍原长的线性结构。如ABC环形结构转换成ABCABC的线性结构。

注意,在解题时我们应把它完全当做是一个线性结构,只在输出的时候有所区别。再注意:循环顺序。

可得到状态转移方程:a[i][j]=max(a[i][j],a[i][l]+a[l+1][j]+sum[j]-sum[i-1]);            b[i][j]=min(b[i][j],b[i][l]+b[l+1][j]+sum[j]-sum[i-1]);   

Task3:能量项链(NOIP2006)

在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m*r*n(Mars单位),新产生的珠子的头标记为m,尾标记为n。

需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设N=4,4颗珠子的头标记与尾标记依次为(2,3) (3,5) (5,10) (10,2)。我们用记号⊕表示两颗珠子的聚合操作,(j⊕k)表示第j,k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为:

(4⊕1)=10*2*3=60。

这一串项链可以得到最优值的一个聚合顺序所释放的总能量为

((4⊕1)⊕2)⊕3)=10*2*3+10*3*5+10*5*10=710。

这道题和石子合并极为相似,整体思路差不多,只要细心找出状态转移方程即可AC。

 a[i][j]=max(a[i][j],a[i][l]+a[l+1][j]+name[i]*name[l+1]*name[j+1]);   name【n】表示第n位上的数。

另附task2代码:

#include<bits/stdc++.h>
using namespace
std;

const int MAXN=200;
int a[MAXN*2][MAXN*2],b[MAXN*2][MAXN*2],sum[MAXN*2],n;

int
main(){

    int x;

    memset(a,0,sizeof(a));

    memset(b,127/3,sizeof(b));

    scanf("%d",&n);

    for(int i=1;i<=2*n;i++)

    {

        b[i][i]=0;

    }

    for(int i=1;i<=n;i++){

        scanf("%d",&x);

        sum[i]=sum[i-1]+x;

    }

    for(int i=n+1;i<=2*n;i++){

        sum[i]=sum
+sum[i-n];

    }

    for(int i=2*n-1;i>=1;i--)

        for(int j=i+1;j<=2*n;j++)

            for(int l=i;l<j;l++){

                a[i][j]=max(a[i][j],a[i][l]+a[l+1][j]+sum[j]-sum[i-1]);

                b[i][j]=min(b[i][j],b[i][l]+b[l+1][j]+sum[j]-sum[i-1]);   

                }

    int ans=0,ss=0x7fffffff;

    for(int i=1;i<=n+1;i++)

    {    int j=i+n-1;

        ans=max(ans,a[i][j]);

        ss=min(ss,b[i][j]);

    }

    printf("%d\n",ss);

    printf("%d\n",ans);

    return 0;

}   

task3代码:

#include
<bits/stdc++.h>
using namespace
std;
const int N=200;
int a[N*2][N*2],name[N*2];
int
main(){   
int n;

    memset(a,0,sizeof(a));

    cin>>n;

    for(int i=1;i<=n;i++)cin>>name[i];

    for(int i=n+1;i<=2*n;i++)name[i]=name[i-n];

    for(int i=2*n-1;i>=1;i--)

        for(int j=i+1;j<=2*n;j++)

            for(int l=i;l<j;l++)

            {

            a[i][j]=max(a[i][j],a[i][l]+a[l+1][j]+name
c93d
[i]*name[l+1]*name[j+1]);   

            }

    int maxx=0;

    for(int i=1;i<=n;i++)

    {

        int j=i+n-1;

        maxx=max(a[i][j],maxx);

    }

    cout<<maxx;

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  区间DP