【Luogu】【关卡2-16】线性动态规划(2017年10月)【还差三道题】
任务说明:这也是基础的动态规划。是在线性结构上面的动态规划,一定要掌握。
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月)【还差三道题】的更多相关文章
- 【Luogu】【关卡2-11】简单数学问题(2017年10月)【还差三道题】
火星人 麦森数 P1403 [AHOI2005]约数研究 f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和. 解答:有几个1做约数的个数 = n /1; 有几个2做约数的个数 = ...
- 【Luogu】【关卡2-6】贪心(2017年10月)
任务说明:贪心就是只考虑眼前的利益.对于我们人生来说太贪是不好的,不过oi中,有时是对的. P1090 合并果子 有N堆果子,只能两两合并,每合并一次消耗的体力是两堆果子的权重和,问最小消耗多少体力. ...
- 【Luogu】【关卡2-3】排序(2017年10月) 【AK】
任务说明:将杂乱无章的数据变得有规律.有各种各样的排序算法,看情况使用. 这里有空还是把各种排序算法总结下吧.qsort需要会写.. P1177 [模板]快速排序 这个题目懒得写了,直接sort了.. ...
- 欢迎来怼-Alpha周(2017年10月19)贡献分配规则和分配结果
.从alpha周(2017年10月19日开始的2周)开始,提高贡献分比重. 贡献分 : 团队分 = 1 : 5 教师会在核算每位同学总分时按比例乘以系数. 每位同学带入团队贡献分10分,如果团队一共7 ...
- 2017年10月31日结束Outlook 2007与Office 365的连接
2017 年10月31日 ,微软即将推出 Office 365中Exchange Online邮箱将需要Outlook for Windows的连接,即通过HTTP Over MAPI方式,传统使用R ...
- 江西省移动物联网发展战略新闻发布会举行-2017年10月江西IDC排行榜与发展报告
编者按:当人们在做技术创新时,我们在做“外包产业“:当人们在做制造产业,我们在做”服务产业“:江人们在做AI智能时,我们在做”物联网“崛起,即使有一个落差,但红色热土从不缺少成长激情. 本期摘自上月初 ...
- 【Luogu】【关卡2-15】动态规划的背包问题(2017年10月)【还差一道题】
任务说明:这是最基础的动态规划.不过如果是第一次接触会有些难以理解.加油闯过这个坎. 01背包二维数组优化成滚动数组的时候有坑有坑有坑!!!必须要downto,downto,downto 情景和代码见 ...
- 【Luogu】【关卡2-13】线性数据结构(2017年10月)【还差一道题】
任务说明:数组,链表,队列,栈,都是线性结构.巧用这些结构可以做出不少方便的事情. P1996 约瑟夫问题 n个人,排成环形,喊到m的人出列,输出出列顺序. 咳咳,这个题目不好写,尽管简单就是模拟题. ...
- 【Luogu】【关卡2-9】带有技巧的搜索(2017年10月)
任务说明:这里的搜索不仅包含了dfs和bfs,还包括剪枝.记录等技巧以加快速度. [USACO06FEB]数字三角形Backward Digit Su… 滑雪 吃奶酪 靶形数独 P1118 [USAC ...
随机推荐
- .360doc.com dot.net技术架构
- 二、bootstrap缩略图幅
一.bootstrap缩略图幅
- mocha.js
mocha 如果你听说过“测试驱动开发”(TDD:Test-Driven Development),单元测试就不陌生. 单元测试是用来对一个模块.一个函数或者一个类来进行正确性检验的测试工作. 比如对 ...
- Java:新建数组
Array Initialization int[] a; = int a[]; int[] a = new int[100]; a[]的值会被初始化为0 `int[] smallPrimes = { ...
- hdu 6085 Rikka with Candies (set计数)
Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...
- 【Flutter学习】基本组件之BottomNavigationBar底部导航栏
一,概述 BottomNavigationBar即是底部导航栏控件,显示在页面底部的设计控件,用于在试图切换,底部导航栏包含多个标签.图标或者两者搭配的形式,简而言之提供了顶级视图之间的快速导航. 二 ...
- ajax中回调的几个坑
在前端开发中,经常要用ajax去拿后台接口返回的数据,总结几个ajax的回调的常见问题,供大家参考爬坑. 未定义contentType,可能会造成的传入后台的数据乱码,可以加上如下代码在ajax请求中 ...
- 【Tomcat】使用Tomcat部署Spring Boot项目生成的jar包
介绍 简单来说,Tomcat是一个免费的,用于Java Web应用以及其它Web应用的一个Web服务器.(简单地概括一下,可能有误) 下载与安装 本文章目标是把Spring Boot Web项目生成的 ...
- (转)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 ...
- 个人笔记 - Word2013 论文格式调整
1.如何实现每章奇偶页页眉不同 2.参考文献自动编号.交叉引用及在正文中自动更新 <1>在要插入引用上标的地方点击“插入”——>“交叉引用” <2>设置引用类型为“编号项 ...