任务说明:这也是基础的动态规划。是在线性结构上面的动态规划,一定要掌握。

P1020 导弹拦截

导弹拦截

P1091 合唱队形

老师给同学们排合唱队形。N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。

合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...<Ti>Ti+1>…>TK(1<=i<=K)。

解答:前面是LIS, 后面是LDS,枚举每一个中心点的位置,求出来之后长度相加,然后减一下。O(nlogn)的LIS还是不会写。用O(N^2)做的。

 #include <bits/stdc++.h>
using namespace std; int N; int calLis(int height[], int endd) {
int dp[endd + ];
for (int i = ; i <= endd; ++i) {
dp[i] = ;
for (int j = ; j < i; ++j) {
if (height[i] > height[j]) {
dp[i] = max(dp[i], dp[j]+);
}
}
}
int answer = ;
for (int i = ; i < endd + ; ++i) {
answer = max(answer, dp[i]);
}
return answer;
} int calLds(int height[], int start) {
int dp[N];
memset(dp, , sizeof(dp));
for (int i = start; i < N; ++i) {
dp[i] = ;
for (int j = start; j < i; ++j) {
if (height[i] < height[j]) {
dp[i] = max(dp[i], dp[j] + );
}
}
}
int answer = ;
for (int i = start; i < N; ++i) {
answer = max(answer, dp[i]);
}
return answer;
} int main () {
cin >> N;
int height[N];
for (int i = ; i < N; ++i) {
cin >> height[i];
} int max_len = ;
for (int i = ; i < N; ++i) {
int len = ;
if (i == ) {
len = calLds(height, );
} else if (i == N - ) {
len = calLis(height, N-);
} else {
len = calLis(height, i) + calLds(height, i+);
}
max_len = max(max_len, len);
}
cout << N - max_len << endl;
return ;
}

尼克的任务

P1880 石子合并-------(这个就是区间dp)

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分。

这个题目做的我好绝望啊...不会不会不会,消耗了一个下午orz

解答:

首先我们先不管是不是环形的操场,直接看成一条线段。

假设只有一堆或者两堆石子, 那么只有一种方案。

那么假设有三堆石子呢,((1, 2),3) ;(1,( 2,3))。

如果有k堆石子呢?-------- 最终都会变成两堆。如果我们把最后两堆分开,左边和右边无论怎么合并,都必须满足最优合并方案,整个问题才能得到最优解

• 每次只能合并相邻的两堆 → 合并成一个点的一定是一个区间

• 每次的得分 → 如果确定了当前区间的起点和重点,得分就是这个区间内石子的总数量

所以转移方程如下:

• T[i][j]:从第 i 堆到第 j 堆的石子数的总和

• F[i][j]:从第 i 堆石子合并到第 j 堆石子的最小的得分

• F[i][j] = min { F[i][k] + F[k+1][j] + t[i][j] } ( i <= k < j )

• 复杂度O(n^3)

最后处理一下环形怎么办:

方法1: 枚举起点 — O(n^4)

方法2:把长度变成2*n — O(8n^3) = O(n^3)

 //区间DP
#include <bits/stdc++.h> using namespace std; int arr[];
int t[]; // t[i] 表示前i堆石子的总数(前缀和)
int dp_min[][]; // dp[i][j] 表示第i堆到第j堆的最小||最大代价
int dp_max[][]; // dp[i][j] 表示第i堆到第j堆的最小||最大代价 void print(int T[][], int N) {
for (int i = ; i < * N; ++i) {
for (int j = ; j < * N; ++j) {
if (T[i][j] == 0x7F7F7F7F) {
printf("INF ");
} else {
printf("%3-d ", T[i][j]);
}
}
printf("\n");
}
} void print(int T[], int N) {
for (int i = ; i <= * N; ++i) {
printf("%d ", T[i]);
}
printf("\n");
} int main() {
int N;
cin >> N; for (int i = ; i < N; ++i) {
cin >> arr[i];
arr[i+N] = arr[i]; //2*N, 拆环为链
} memset(t, , sizeof(t));
for (int i = ; i <= * N; ++i) {
t[i] = t[i-] + arr[i-];
}
memset(dp_min, 0x7F, sizeof(dp_min));
memset(dp_max, , sizeof(dp_max));
/*
printf("=======debug========T done=========\n");
print(t, N);
printf("=======debug========dp_min init=========\n");
print(dp_min, N);
printf("=======debug========dp_max init=========\n");
print(dp_max, N);
*/
for (int i = *N - ; i >= ; --i) {
for (int j = i; j < *N; ++j) {
if (i == j) {
dp_min[i][i] = dp_max[i][i] = ;
} else {
for (int k = i; k < j; ++k) {
dp_min[i][j] = min(dp_min[i][j], dp_min[i][k] + dp_min[k+][j] + t[j+] - t[i]);
dp_max[i][j] = max(dp_max[i][j], dp_max[i][k] + dp_max[k+][j] + t[j+] - t[i]);
}
}
}
}
/*
printf("=======debug========dp_min done=========\n");
print(dp_min, N);
printf("=======debug========dp_max done=========\n");
print(dp_max, N);
*/
int ans_maxx = , ans_minn = INT_MAX;
for (int i = ; i < N; ++i) {
if (dp_max[i][N+i-] > ans_maxx) {
ans_maxx = dp_max[i][N+i-];
}
if (dp_min[i][N+i-] < ans_minn) {
ans_minn = dp_min[i][N+i-];
}
}
cout << ans_minn << endl << ans_maxx << endl;
return ;
}

P1108 低价购买

题意就是给出 N 天的股票价格, 购买的原则是 【低价购买,再低价购买】, 求出最大购买次数和拥有最大购买次数的方案数(要求价格序列一致的时候要去重)。

解答:第一问:最长下降子序列的长度。(模板)    第二问:求去重后的方案数。(难点)

看了题解,学习了下答案:

设置一个methods[i]数组, 表示以price[i]为结尾的序列的最大购买方案数。

如果说 price[i] == price[j] && dp[i] == dp[j] && i > j , 那么就把 method[j] = 0. //解释一下就是如果有两天价格一样,并且这两天的LDS也一样,就把一天的方案数置为0.

为什么需要置前一天的方案数为0,而不是后一天? -->  因为能转移到前一天的方案 也一定能转移到后一天, 反之不行。

举个例子: price = [9 , 8 , 10, 8, 1]  -> dp = [1, 2, 1, 2, 3] -> price有两个8。第一个8的方案数是 1 (对应的方案是 【9, 8】), 第二个8的方案数其实是 2 (对应的方案是 【9, 8】【10, 8】)。 因为【9, 8】 就是重复的,所以把第一个8的methods置为0。

 // P1108 低价购买
#include <bits/stdc++.h> using namespace std; int main() {
int N;
cin >> N;
int price[N];
for (int i = ; i < N; ++i) {
cin >> price[i];
} //[1] 用LIS来计算dp数组
int dp[N];
int ans_length = ; //一开始边界写成0了,82分.. 最短的长度就是1
for (int i = ; i < N; ++i) {
dp[i] = ;
for (int j = ; j < i; ++j) {
if (price[i] < price[j]) {
dp[i] = max(dp[i], dp[j] + );
ans_length = max (dp[i], ans_length);
}
}
}
//[2] 求方案数 || 怎么去重是关键.
int methods[N];
for (int i = ; i < N; ++i) {
methods[i] = ;
if (dp[i] == ) {
methods[i] = ;
//continue; 写了continue会wa
//举个例子 price数组是 [2, 1, 2, 3], 计算出来的dp数组是 [1, 2, 1, 1]; 其实method数组应该是 [0, 1, 1, 1];
//但是如果continue的话就是 [1, 1, 1, 1]
}
for (int j = ; j < i; ++j) {
// 难点---如何去重的分支
if (price[i] == price[j] && dp[i] == dp[j]) {
methods[j] = ;
}
else if (price[i] < price[j] && dp[i] == dp[j]+) {
methods[i] += methods[j];
}
}
} int ans_methods = ;
for (int i = ; i < N; ++i) {
if (dp[i] == ans_length) {
ans_methods += methods[i];
}
}
cout << ans_length << " " << ans_methods << endl;
return ;
}

多米诺骨牌

【Luogu】【关卡2-16】线性动态规划(2017年10月)【还差三道题】的更多相关文章

  1. 【Luogu】【关卡2-11】简单数学问题(2017年10月)【还差三道题】

    火星人 麦森数 P1403 [AHOI2005]约数研究 f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和. 解答:有几个1做约数的个数 = n /1; 有几个2做约数的个数 = ...

  2. 【Luogu】【关卡2-6】贪心(2017年10月)

    任务说明:贪心就是只考虑眼前的利益.对于我们人生来说太贪是不好的,不过oi中,有时是对的. P1090 合并果子 有N堆果子,只能两两合并,每合并一次消耗的体力是两堆果子的权重和,问最小消耗多少体力. ...

  3. 【Luogu】【关卡2-3】排序(2017年10月) 【AK】

    任务说明:将杂乱无章的数据变得有规律.有各种各样的排序算法,看情况使用. 这里有空还是把各种排序算法总结下吧.qsort需要会写.. P1177 [模板]快速排序 这个题目懒得写了,直接sort了.. ...

  4. 欢迎来怼-Alpha周(2017年10月19)贡献分配规则和分配结果

    .从alpha周(2017年10月19日开始的2周)开始,提高贡献分比重. 贡献分 : 团队分 = 1 : 5 教师会在核算每位同学总分时按比例乘以系数. 每位同学带入团队贡献分10分,如果团队一共7 ...

  5. 2017年10月31日结束Outlook 2007与Office 365的连接

    2017 年10月31日 ,微软即将推出 Office 365中Exchange Online邮箱将需要Outlook for Windows的连接,即通过HTTP Over MAPI方式,传统使用R ...

  6. 江西省移动物联网发展战略新闻发布会举行-2017年10月江西IDC排行榜与发展报告

    编者按:当人们在做技术创新时,我们在做“外包产业“:当人们在做制造产业,我们在做”服务产业“:江人们在做AI智能时,我们在做”物联网“崛起,即使有一个落差,但红色热土从不缺少成长激情. 本期摘自上月初 ...

  7. 【Luogu】【关卡2-15】动态规划的背包问题(2017年10月)【还差一道题】

    任务说明:这是最基础的动态规划.不过如果是第一次接触会有些难以理解.加油闯过这个坎. 01背包二维数组优化成滚动数组的时候有坑有坑有坑!!!必须要downto,downto,downto 情景和代码见 ...

  8. 【Luogu】【关卡2-13】线性数据结构(2017年10月)【还差一道题】

    任务说明:数组,链表,队列,栈,都是线性结构.巧用这些结构可以做出不少方便的事情. P1996 约瑟夫问题 n个人,排成环形,喊到m的人出列,输出出列顺序. 咳咳,这个题目不好写,尽管简单就是模拟题. ...

  9. 【Luogu】【关卡2-9】带有技巧的搜索(2017年10月)

    任务说明:这里的搜索不仅包含了dfs和bfs,还包括剪枝.记录等技巧以加快速度. [USACO06FEB]数字三角形Backward Digit Su… 滑雪 吃奶酪 靶形数独 P1118 [USAC ...

随机推荐

  1. .360doc.com dot.net技术架构

  2. 二、bootstrap缩略图幅

    一.bootstrap缩略图幅

  3. mocha.js

    mocha 如果你听说过“测试驱动开发”(TDD:Test-Driven Development),单元测试就不陌生. 单元测试是用来对一个模块.一个函数或者一个类来进行正确性检验的测试工作. 比如对 ...

  4. Java:新建数组

    Array Initialization int[] a; = int a[]; int[] a = new int[100]; a[]的值会被初始化为0 `int[] smallPrimes = { ...

  5. hdu 6085 Rikka with Candies (set计数)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  6. 【Flutter学习】基本组件之BottomNavigationBar底部导航栏

    一,概述 BottomNavigationBar即是底部导航栏控件,显示在页面底部的设计控件,用于在试图切换,底部导航栏包含多个标签.图标或者两者搭配的形式,简而言之提供了顶级视图之间的快速导航. 二 ...

  7. ajax中回调的几个坑

    在前端开发中,经常要用ajax去拿后台接口返回的数据,总结几个ajax的回调的常见问题,供大家参考爬坑. 未定义contentType,可能会造成的传入后台的数据乱码,可以加上如下代码在ajax请求中 ...

  8. 【Tomcat】使用Tomcat部署Spring Boot项目生成的jar包

    介绍 简单来说,Tomcat是一个免费的,用于Java Web应用以及其它Web应用的一个Web服务器.(简单地概括一下,可能有误) 下载与安装 本文章目标是把Spring Boot Web项目生成的 ...

  9. (转)Android Studio解决unspecified on project app resolves to an APK archive which is not supported

    出现该问题unspecified on project app resolves to an APK archive which is not supported as a compilation d ...

  10. 个人笔记 - Word2013 论文格式调整

    1.如何实现每章奇偶页页眉不同 2.参考文献自动编号.交叉引用及在正文中自动更新 <1>在要插入引用上标的地方点击“插入”——>“交叉引用” <2>设置引用类型为“编号项 ...