poj 3666 Making the Grade (线性结构上的DP )

意:

给定n个数,问你将他们修改成非增或非减序列的最小花费。最小花费的定义是 

假设原数组为 a[1] a[2] a[3] .... a[n]

修改后数组为 b[1] b[2] b[3] .... b[n]

那么最小花费为|a[1]-b[1]|+|a[2]-b[2]|+| a[3] - b[3] |+.....| a[n] - b[n] |.

思路:

线性结构上的动态规划 定义状态d[i][j] 表示 前i-1个数字已经是最小花费 现在把第i个数修改成b[j] 修改完成后前i个数总共最少需要的花费是多少

状态转移 见代码

或者看这个链接:http://www.hankcs.com/program/cpp/poj-3666-making-the-grade.html

值得注意的是 不知道是我理解错题意还是有些人做错了 弱感觉他们只考虑了非减的情况 但是却AC了。他们的代码是不能解决 3 2 1 这个样例的...弱以为应该输出0才对啊;

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn = 2005;
int n;
int a[maxn], b[maxn];
int dp[maxn][maxn];

bool cmp1(int a1, int a2){
    return a1 > a2;
}
void init(){
    int tmp;
    for(int i = 1; i <= n; i++){
        scanf("%d",&tmp);
        a[i] = b[i] = tmp;
    }
    sort(b+1, b+n+1);
}
void solve(){
    memset(dp,0,sizeof(dp));
    for(int i = 1; i <= n; i++){
        dp[1][i] = abs(a[1] - b[i]);
    }
    for(int i = 2; i <= n; i++){
        int min_cost = dp[i-1][1];
        for(int j = 1; j <= n; j++){
            min_cost = min(min_cost, dp[i-1][j]);
            dp[i][j] = min_cost + abs(a[i] - b[j]);
        }
    }
    int ans1 = dp[n][1];
    for(int i = 2; i <= n; i++){
        ans1 = min(ans1, dp[n][i]);
    }
    sort(b+1, b+n+1, cmp1);
    memset(dp,0,sizeof(dp));
    for(int i = 1; i <= n; i++){
        dp[1][i] = abs(a[1] - b[i]);
    }
    for(int i = 2; i <= n; i++){
        int min_cost = dp[i-1][1];
        for(int j = 1; j <= n; j++){
            min_cost = min(min_cost, dp[i-1][j]);
            dp[i][j] = min_cost + abs(a[i] - b[j]);
        }
    }
    int ans2 = dp[n][1];
    for(int i = 2; i <= n; i++){
        ans2 = min(ans2, dp[n][i]);
    }
    printf("%d\n",min(ans1, ans2));
}
int main(){
    while(scanf("%d",&n) != EOF){
        init();
        solve();
    }
    return 0;
}
/*
3
3 2 1
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值