状态机dp

有两种状态:加一维0/1,分别dp
注:
正无穷0x3f3f3f3f
memset(dp,0x3f,sizeof(dp));
负无穷0xcf
memset(dp,0xcf,sizeof(dp));

Q1
http://codeforces.com/contest/1418/problem/C

C. Mortal Kombat Tower time limit per test1 second memory limit per
test256 megabytes inputstandard input outputstandard output You and
your friend are playing the game Mortal Kombat XI. You are trying to
pass a challenge tower. There are n bosses in this tower, numbered
from 1 to n. The type of the i-th boss is ai. If the i-th boss is easy
then its type is ai=0, otherwise this boss is hard and its type is
ai=1.

During one session, either you or your friend can kill one or two
bosses (neither you nor your friend can skip the session, so the
minimum number of bosses killed during one session is at least one).
After your friend session, your session begins, then again your friend
session begins, your session begins, and so on. The first session is
your friend’s session.

Your friend needs to get good because he can’t actually kill hard
bosses. To kill them, he uses skip points. One skip point can be used
to kill one hard boss.

Your task is to find the minimum number of skip points your friend
needs to use so you and your friend kill all n bosses in the given
order.

For example: suppose n=8, a=[1,0,1,1,0,1,1,1]. Then the best course of
action is the following:

your friend kills two first bosses, using one skip point for the first
boss; you kill the third and the fourth bosses; your friend kills the
fifth boss; you kill the sixth and the seventh bosses; your friend
kills the last boss, using one skip point, so the tower is completed
using two skip points. You have to answer t independent test cases.

Input The first line of the input contains one integer t (1≤t≤2⋅104) —
the number of test cases. Then t test cases follow.

The first line of the test case contains one integer n (1≤n≤2⋅105) —
the number of bosses. The second line of the test case contains n
integers a1,a2,…,an (0≤ai≤1), where ai is the type of the i-th boss.

It is guaranteed that the sum of n does not exceed 2⋅105 (∑n≤2⋅105).

Output For each test case, print the answer: the minimum number of
skip points your friend needs to use so you and your friend kill all n
bosses in the given order.

Example input 6 8 1 0 1 1 0 1 1 1 5 1 1 1 1 0 7 1 1 1 1 0 0 1 6 1 1 1
1 1 1 1 1 1 0 output 2 2 2 2 1 0

误解:贪心
0 0 0 1 1
全局最优解不一定是局部最优解
正解:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 200005;
int dp[MAXN][2], a[MAXN];
int n, m;

int main() {
#ifdef LOCAL
    freopen("zz_in.txt", "r", stdin);
    freopen("zz_op.txt", "w", stdout);
#endif
    int t, i, j, k;
    cin >> t;
    while (t--) {
        memset(a, 0, sizeof(a));
        memset(dp, 0x3f, sizeof(dp));
        cin >> n;
        for (i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        dp[1][0] = a[1];
        dp[2][0] = a[1] + a[2];
        dp[2][1] = a[1];
        for (i = 3; i <= n; i++) {
            dp[i][0] = min(dp[i - 1][1] + a[i], dp[i - 2][1] + a[i - 1] + a[i]);
            dp[i][1] = min(dp[i - 1][0], dp[i - 2][0]);
        }
        cout << min(dp[n][0], dp[n][1]) << endl;
    }

#ifdef LOCAL
    printf("Time used = %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}

Q2:(acwing1057)

给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润,你最多可以完成 k 笔交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。一次买入卖出合为一笔交易。

输入格式 第一行包含整数 N 和 k,表示数组的长度以及你可以完成的最大交易数量。

第二行包含 N 个不超过 10000 的正整数,表示完整的数组。

输出格式 输出一个整数,表示最大利润。

数据范围 1≤N≤105, 1≤k≤100
输入样例1: 3 2 2 4 1
输出样例1: 2
输入样例2: 6 2 3 2 6 5 0 3
输出样例2: 7
样例解释 样例1:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4)
的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。

样例2:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2
= 4 。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。共计利润 4+3 = 7.

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 100006;
int n, m, k;
int a[MAXN];
int dp[2][105][2];
int main() {
#ifdef LOCAL
    freopen("zz_in.txt", "r", stdin);
    freopen("zz_op.txt", "w", stdout);
#endif
    cin >> n >> k;
    memset(dp, 0xcfcfcf, sizeof(dp));
    dp[0][0][0] = 0;
    dp[0][0][1] = 0;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    // dp[0][1][0] = a[2] - a[1];

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= k; j++) {
            dp[0][j][i % 2] = max(dp[0][j][(i + 1) % 2], dp[1][j][(i + 1) % 2] + a[i]);
            dp[1][j][i % 2] = max(dp[1][j][(i + 1) % 2], dp[0][j - 1][(i + 1) % 2] - a[i]);
        }
    }
    int ans = 0;
    for (int i = 1; i <= k; i++) {
        ans = max(ans, dp[0][i][n % 2]);
    }
    cout << ans << endl;

#ifdef LOCAL
    printf("Time used = %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值