成环间隔01背包

#include <bits/stdc++.h>
using namespace std;
//算法提高 种树
//这是01背包问题的变形
//环的处理方法 1.找到最小值的位置,预处理数组,比如 56 21 64 32 45 -> 21 64 32 45 56 21
//这样就相邻了而且21 21肯定不会同时选到
//2.还可以:第一个和最后一个只会选一个,
//那么就对 1...n-1 2...n进行处理,然后求最大值,注意要求两次dp,不是一次完成
int dp[101][101]={0},n,m,a[101][101]={0},v[101],v1[101];
int main()
{   
    int min=1;
    cin>>n>>m;
    for(int i=1;i<=n;i++) {
        cin>>v1[i];
        if(v1[i]<v1[min]) min=i;
    }
    if(n/2<m) {cout<<"Error!\n";return 0;}
    for(int i=min;i<=n;i++) v[i-min+1]=v1[i];
    for(int i=1;i<=min;i++) v[n-min+i+1]=v1[i];
    n++;
    dp[n][1]=v[n];
    a[n][1]=n;
    //这个是定义a的做法,a存放对应的dp数组的最左边位置的index
    // for(int i=n-1;i>=1;i--){
    //     for(int j=1;j<=m;j++){
    //         if(j>(n-i+1)/2) continue;
    //         if(dp[i+1][j]>dp[i][j]){
    //             dp[i][j]=dp[i+1][j];
    //             a[i][j]=a[i+1][j];
    //         }
    //         if(a[i+2][j-1]!=i+1){
    //             if(dp[i+2][j-1]+v[i]>dp[i][j]){
    //                 dp[i][j]=dp[i+2][j-1]+v[i];
    //                 a[i][j]=i;
    //             }
    //         } 
    //     }
    // }

    //也可以不定义a,因为dp[i+2][j-1]已经代表着不相邻了。
    for(int i=n-1;i>=1;i--){
        for(int j=1;j<=m;j++){
            if(j>(n-i+1)/2) continue;
            dp[i][j]=max(dp[i+1][j],dp[i+2][j-1]+v[i]);
        }
    }

    cout<<dp[1][m]<<endl;
    return 0;
}

 

posted @ 2020-06-06 20:54  西伯利亚挖土豆  阅读(118)  评论(0编辑  收藏  举报