ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

区间DP:基因拼接

2021-06-02 11:32:15  阅读:172  来源: 互联网

标签:DNA temp Min int Max sum 基因 拼接 DP


5(选做) 基因拼接 (100 分)
基因拼接是将不同的DNA片段连接在一起。现有n个DNA片段,从左到右排成一条直线。每次选取相邻的两个DNA片段,拼接成一条更长DNA片段。规定最后1个DNA片段和第1个DNA片段相邻。重复这个过程,直到所有的DNA片段形成一个DNA片段。每次拼接,花费的代价是所选两个DNA片段的长度之和。现在想知道,上述基因拼接,花费的最小代价和最大代价分别是多少。

输入格式:
第1行,一个整数n,表示DNA片段的个数,1≤n≤200。

第2行,n个整数Li,用空格分隔,Li表示第i个DNA片段的长度,1≤Pi≤100,1≤i≤n。

输出格式:
1行,两个整数,用空格分隔,表示所求的最小代价和最大代价。

输入样例:
在这里给出一组输入。例如:

3
1 3 2
输出样例:
在这里给出相应的输出。例如:

9 11

说来惭愧,一直以为这个题目是一个贪心就完了。看似显然的东西,实际上根本就没办法证明是贪心。我一开始的思路就是看哪一个最小,就走哪一个合并,哪一个最大就走哪一个,最后算出来最小和最大。分析一下自己的思路往那方面偏差的原因,大概是在于我,第一眼就觉得这个题目是和“合并果子是一类的题目”。自以为掌握了题目精髓?
但是,咨询别的大佬之后,才知道这是一个区间DP问题。
设置一个dp[i][j]表示区间的最小代价或者最大代价,然后有个不错的技巧学到了,把序列1 2 3 4 5变成1 2 3 4 5 1 2 3 4就可以模拟所有环的情况了。避免了很复杂的环的处理。然后,这个代码并不是一次就成功的,因为递推关系式子并没有写好。
正确的递推关系式是这样的:
s u m sum sum表示前缀和,所以现在看来,突然发现我代码写的不太好,下面是第一版的代码了,我要更新一个第二版出来。
D P [ i ] [ j ] = m a x i ≤ k < j    { D P [ i ] [ k ] + D P [ k + 1 ] [ j ] + s u m [ j ] − s u m [ i − 1 ] } DP[i][j]=max_{i\leq k< j \,\,}\{DP[i][k]+DP[k+1][j]+sum[j]-sum[i-1]\} DP[i][j]=maxi≤k<j​{DP[i][k]+DP[k+1][j]+sum[j]−sum[i−1]}

#include<bits/stdc++.h>
using namespace std;
int f[410][410];
int input[1000];
int sum[210];
int n;
int main(){
    scanf("%d",&n);
    if(n==1){
        scanf("%d",&n);
        printf("0 0");
        return 0;
    }
    for(int i=1;i<=n;i++)
        scanf("%d",&input[i]);
    for(int j=n+1;j<=2*n-1;j++)
        input[j]=input[j-n];
    for(int i=1;i<=2*n-1;i++)
        sum[i]=sum[i-1]+input[i];
    for(int i=2*n-1;i>=1;i--)
    {
        f[i][i]=input[i];
        for(int j=i+1;j<=i+n-1&&j<=2*n-1;j++)
        {
            if(j==i+1)
            {
                f[i][j] =sum[j]-sum[i-1];
            }
            else
            {
                int Min=INT_MAX;
                for(int k = i; k < j; k++)
                {
                    int temp_Min=sum[j]-sum[i-1];
                    if(i!=k) temp_Min+=f[i][k];
                    if((k+1)!=j) temp_Min+=f[k+1][j];
                    Min = min(Min,temp_Min);
                }
                f[i][j] = Min;
            }
        }
    }
    int Min=INT_MAX;
    for(int i=1;i<=n;i++){
        Min=min(Min, f[i][i+n-1]);
    }
    printf("%d ",Min);

    for(int i=2*n-1;i>=0;i--)
    {
        f[i][i] = input[i];
        for (int j=i+1;j<=2*n-2;j++)
        {
            if(j==i+1)
            {
                f[i][j] =sum[j]-sum[i-1];
            }
            else
            {
                int Max=INT_MIN;
                for(int k = i; k < j; k++)
                {
                    int temp_Max=sum[j]-sum[i-1];
                    if(i!=k) temp_Max+=f[i][k];
                    if((k+1)!=j) temp_Max+=f[k+1][j];
                    Max = max(Max, temp_Max);
                }
                f[i][j] = Max;
            }
        }
    }
    int Max=INT_MIN;
    for(int i=1;i<=n;i++){
        Max=max(Max, f[i][i+n-1]);
    }
    printf("%d",Max);
    return 0;
}

第二版的代码出炉:
之前改动的地方只有一个,那就是这个f[i][i]到底是等于多少,实际上就应该是0,这样的话特判都可以去掉了,还是自己题意理解不到位,竟然现在才发现这个问题。果然反思还是有很大作用的(思考.jpg)。
emmm其实这个类型的题目我也做过,LeetCode叫做奇怪的打印机
https://leetcode-cn.com/problems/strange-printer/
可惜还是整合不到一起去。这个是硬伤啊,这类型的题目看来还是有很多可以探索的。所以,还差的远呢。

#include<bits/stdc++.h>
using namespace std;
int f[410][410];
int input[1000];
int sum[210];
int n;
int main(){
    scanf("%d",&n);

    for(int i=1;i<=n;i++)
        scanf("%d",&input[i]);
    for(int j=n+1;j<=2*n-1;j++)
        input[j]=input[j-n];
    for(int i=1;i<=2*n-1;i++)
        sum[i]=sum[i-1]+input[i];

    for(int i=2*n-1;i>=1;i--)
    {
        for(int j=i+1;j<=i+n-1&&j<=2*n-1;j++)
        {
            if(j==i+1)
                f[i][j] =sum[j]-sum[i-1];
            else
            {
                int Min=INT_MAX;
                for(int k = i; k < j; k++)
                {
                    int temp_Min=f[i][k]+f[k+1][j]+sum[j]-sum[i-1];
                    Min = min(Min,temp_Min);
                }
                f[i][j] = Min;
            }
        }
    }
    int Min=INT_MAX;
    for(int i=1;i<=n;i++)
        Min=min(Min, f[i][i+n-1]);
    printf("%d ",Min);
    for(int i=2*n-1;i>=0;i--)
    {
        for (int j=i+1;j<=2*n-2;j++)
        {
            if(j==i+1)
                f[i][j] =sum[j]-sum[i-1];
            else
            {
                int Max=INT_MIN;
                for(int k = i; k < j; k++)
                {
                    int temp_Max=f[i][k]+f[k+1][j]+sum[j]-sum[i-1];
                    Max = max(Max, temp_Max);
                }
                f[i][j] = Max;
            }
        }
    }
    int Max=INT_MIN;
    for(int i=1;i<=n;i++)
        Max=max(Max, f[i][i+n-1]);
    printf("%d",Max);
    return 0;
}

标签:DNA,temp,Min,int,Max,sum,基因,拼接,DP
来源: https://blog.csdn.net/weixin_47741017/article/details/117462765

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有