NOIP2006 提高组 复赛 energy 能量项链

NOIP2006 提高组 复赛 energy 能量项链

//觉得想得蛮好,提交,测试点1,4,8,9,10 WA
//提供一组测试数据
//4
//3 2 1 4
//输出
//80
//for(i=1;i+k<=2*n-1;i++)//此处写成for(i=1;i<=n;i++),查了好长时间
//for(i=1;i<=n;i++)只算了1,2,...,n为起始位置的情况
//n+1,n+2,...为起始位置的情况没有计算。 2018-11-1 18:16 
//修改,提交AC。2018-11-1 18:07 
 
#include <stdio.h>
#include <string.h>
#define maxn 220
int f[maxn][maxn],a[maxn];
int max(int a,int b){
    return a>b?a:b;
}
int main(){
    int n,i,j,k,ans=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[n+i]=a[i];
    }
    memset(f,0,sizeof(f));
    //忘记初始化了
     
    for(k=1;k<=n-1;k++)//2个 3个 n个
        for(i=1;i+k<=2*n-1;i++)//此处写成for(i=1;i<=n;i++),查了好长时间//起始序号
            for(j=i;j<i+k;j++)//剖开位置
                f[i][i+k]=max(f[i][i+k],f[i][j]+f[j+1][i+k]+a[i]*a[j+1]*a[i+k+1]);
    for(i=1;i<=n;i++)
        if(ans<f[i][i+n-1])
            ans=f[i][i+n-1];
    printf("%d\n",ans);
    return 0;
}

 

1.读完题目,挺简单的,开个结构体,存储节点的头尾信息。

2.读取数据,记录头尾信息。

3.按顺序进行珠子能量合并,找出最大能量值。

4.提交10分,反复读题,觉得没问题,又觉得有问题,想了想,如果数据给定比较合适,珠子的合并顺序,可以不依照输入顺序进行合并,那该怎么处理呢,好像以目前的知识无能为力啊。

5.上网搜索,果然,说是动态规划问题,那就从头学吧。

6.学习http://wenku.baidu.com/link?url=UDL6fMzYuoXAl35TVnazjoGCIzZ3jUOtITvlitwybrhYNczdnsHMmYFJXb1e1ilxRFbfBdTYEqpcDjB3-gQ0Pf6nF_wItx9JyWKnctAAYsO动态规划:从新手到专家http://blog.csdn.net/hzj379805931/article/details/51050741

附上数硬币对应的代码,根据文中伪代码,第一次用动态规划思想编写程序,很是高兴:

//dp count_coin 非递归
#include <stdio.h>
int v[3]={1,3,5};//币值种类
int min[1000000];
const int inf=999999;
int main(){
    int s;//总金额
    int i,j;
    scanf("%d",&s);//输入总金额
    min[0]=0;
    for(i=1;i<=s;i++)
        min[i]=inf;
    for(i=1;i<=s;i++)
        for(j=0;j<3;j++)
            if(v[j]<=i&&min[i-v[j]]+1<min[i])
                min[i]=min[i-v[j]]+1;
    printf("min[%d]=%d\n",s,min[s]);//输出构成总金额s的最少硬币个数
}

//dp count_coin2 递归
#include <stdio.h>
int v[3]={1,3,5};
int fun(int s){
    int i;
    int min=99999;
    if(s==0)
        return 0;
    for(i=0;i<3;i++)
        if(s>=v[i]&&fun(s-v[i])+1<min)
            min=fun(s-v[i])+1;
    return min;
}
int main(){
    int s;
    scanf("%d",&s);
    printf("%d\n",fun(s));
    return 0;
}

附上最长非降子序列的长度代码(我们定义d(i),表示前i个数中以A[i]结尾的最长非降子序列的长度。

//longest increasing subsqeuence 非递归
#include <stdio.h>
int main(){
    int a[]={5,3,4,8,6,7};
    int n=6;
    int i,j;
    int d[6];
    int maxLen;
    for(i=0;i<n;i++){
        maxLen=1;
        for(j=0;j<i;j++){
            d[i]=maxLen;
            if(a[j]<=a[i]&&d[j]+1>d[i])
                d[i]=d[j]+1;
            if(d[i]>maxLen)
                maxLen=d[i];
        }
        d[i]=maxLen;
    }
    printf("%d\n",d[5]);
    return 0;
}

 

//longest increasing subsequence 递归
#include <stdio.h>
int a[]={5,3,4,8,6,7};
int lis(int n){
    int i,j;
    int maxLen;
    if(n==0)
        return 1;
    maxLen=1;
    for(i=0;i<n;i++)
        if(a[i]<=a[n]&&lis(i)+1>maxLen)
            maxLen=lis(i)+1;
    return maxLen;
}
int main(){
    printf("%d\n",lis(6-1));
}
找到一篇好文,http://blog.csdn.net/qq632544991p/article/details/52434951能将上述内容补齐

松鼠吃苹果,介绍得不错,但输出结果有误。又找了一个http://www.cnblogs.com/zhezh/p/3773284.html

附上苹果代码

//apple 非递归
#include <stdio.h>
int a[100][100];
int s[100][100];
int main(){
    int i,j;
    int row,col;
    scanf("%d%d",&row,&col);
    for(i=0;i<row;i++)
        for(j=0;j<col;j++)
            scanf("%d",&a[i][j]);
    //初始化,第一行,第一列
    s[0][0]=a[0][0];
    for(j=1;j<col;j++)//第一行
        s[0][j]=s[0][j-1]+a[0][j];
    for(i=1;i<row;i++)//第一列
        s[i][0]=s[i-1][0]+a[i][0];
    
    for(i=1;i<row;i++)
        for(j=1;j<col;j++)
            if(s[i][j-1]>s[i-1][j])
                s[i][j]=s[i][j-1]+a[i][j];
            else
                s[i][j]=s[i-1][j]+a[i][j];
    for(i=0;i<row;i++){
        for(j=0;j<col;j++)
            printf("%d\t",s[i][j]);
        printf("\n");
    }
    return 0;
}
输入数据:

3 3
1 2 3
4 5 6
7 8 9
 

输出数据:

1    3    6    
5    10    16    
12    20    29  

//apple 递归
#include <stdio.h>
int a[100][100];
int s[100][100];

int makes(int r,int c){
    if(r==0&&c==0)//第一个数据
        s[r][c]=a[r][c];
    else if(r==0)//第一列
        s[r][c]=makes(r,c-1)+a[r][c];
    else if(c==0)//第一行
        s[r][c]=makes(r-1,c)+a[r][c];
    else{
        if(makes(r,c-1)>makes(r-1,c))
            s[r][c]=makes(r,c-1)+a[r][c];
        else
            s[r][c]=makes(r-1,c)+a[r][c];
    }
    return s[r][c];
}
int main(){
    int i,j;
    int row,col;
    scanf("%d%d",&row,&col);
    for(i=0;i<row;i++)
        for(j=0;j<col;j++)
            scanf("%d",&a[i][j]);
    s[row-1][col-1]=makes(row-1,col-1);
    for(i=0;i<row;i++){
        for(j=0;j<col;j++)
            printf("%d\t",s[i][j]);
        printf("\n");
    }
    return 0;
}

 

能量项链,这几篇文章介绍得不错:

http://blog.sina.com.cn/s/blog_4c396f4301000bol.html

http://blog.csdn.net/a351357741/article/details/6493945

http://blog.sina.com.cn/s/blog_963453200101ketm.html

http://www.cnblogs.com/CYWer/p/4778720.html

着重http://blog.sina.com.cn/s/blog_963453200101ketm.html,可惜程序看不懂,怎么办,祭出跟踪大法,弄明白了,

第一重循环确定,聚合能量珠子总个数

第二重循环确定,第一个聚合珠子的起点位置

第三重循环确定,在起点珠子与终点珠子之间剖开位置。

开始编码,希望能成功。

 

附上AC代码,编译环境Dev-C++4.9.9.2

//2006 energy3
#include <stdio.h>
#include <string.h>
int e[200+20][200+20];
int a[200+20];
int my_max(int a,int b){
    if(a>=b)
        return a;
    else
        return b;
}
int main(){
    int n;
    int i,j,k;
    int t,max_e;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[n+i]=a[i];
    }
    memset(e,0,sizeof(e));//别忘了初始化,e[i][i]=0;
    for(j=1;j<=n-1;j++){//聚合珠子个数j+1
        for(i=1;i+j<=2*n-1;i++){//聚合珠子起点序号
            t=0;
            for(k=0;k<=j-1;k++){//聚合珠子剖开位置
                t=my_max(t,e[i][i+k]+e[i+k+1][i+j]+a[i]*a[i+k+1]*a[i+j+1]);//a[i]容易写成a[i+k]
            }
            e[i][i+j]=t;//此处容易犯错,e[i][j];
        }
    }
    max_e=0;
    for(i=1;i<=n;i++)
        max_e=my_max(max_e,e[i][i+n-1]);
    printf("%d\n",max_e);
    return 0;
}
很明显该题的动态归化难在写代码,不过认清珠子聚合至少两个,至多n个,作为第一重循环,此题就不难了。
2017-1-5 20:04

附上10分代码,编译环境Dev-C++4.9.9.2

//2006 energy 能量项链
#include <stdio.h>
struct node{
    int head;
    int tail;
}d[100+10];
int main(){
    int i,j;
    int n;
    int v;
    int max=-1;
    int e;
    int newhead,newtail;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&v);
        d[i].head=v;
    }
    d[n-1].tail=d[0].head;
    for(i=0;i<n-1;i++)
        d[i].tail=d[i+1].head;
    for(i=0;i<n;i++){
        e=0;
        newhead=d[i].head;
        newtail=d[i].tail;
        for(j=i+1;j<n+i;j++){
            e+=newhead*newtail*d[j%n].tail;
            newtail=d[j%n].tail;
        }
        if(max<e)
            max=e;
    }
    printf("%d\n",max);
    return 0;
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值