DP:Making the Grade(POJ 3666)
题目大意:就是农夫要修一条路,现在要求这条路要么就是上升的,要么就是下降的,总代价为∑|a[i]-b[i]|,求代价最低的修路方案, (0 ≤ β≤ 1,000,000,000) , (1 ≤ N ≤ 2,000)
这一题百分百就是DP了,为什么?我们现在就是要让cost最小,但是我们不知道cost应该怎么才能最小。
我们可以这么想,因为序列总是上升或者下降的,我们可以考虑上升的情况,假设前几个数组成的最大值为β,我们要考虑从0-β的改变值,然后不断推到第n个序列。
显然,这样的复杂度为0(Nβ^2),当然这样的复杂度显然是出事的。
现在我们想着优化这个东西,我们可以这么想,如果我们像之前那样扫描的话,那么其实我们忽略了一个很重要的事实,就是在变到α(α<β),其实对于α+1~β之内不会对α造成影响,于是我们可以用一个最小值的临时变量储存在α之前的最小值,用这个更新dp即可,那样就少了一次扫β的复杂度
复杂度变为O(Nβ);
但是如果仅仅是这样的话,绝对是TLE,因为β实在是太大了。
那么我们就要用到离散化的思想,把β投影到有限区域中,既然β是大小的函数,那么我们把可以这样对应:我们只用把新的序列按从小到大排列,然后只对下标进行查找就可以了,这样我们就把解的空间变到下标中了。
最后状态转移方程:dp[i-1][j]=ABS(a[i]-b[j])+min(dp[i-1][j]);(用滚动数组就可以了)
另外这一题还有一个更快的解法,那就是用左式堆去解,这个我晚一点开一个新的随笔写好了
#include <iostream>
#include <functional>
#include <algorithm>
#define ABS(a,b) (a-b) > 0 ? (a-b):(b-a) using namespace std; static int road[];
static int new_road[];
static long long dp1[];
static long long dp2[]; int fcmop1(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
int fcmop2(const void *a, const void *b)
{
return *(int *)b - *(int *)a;
} long long Search_Increase(const int);
long long Search_Decrease(const int); int main(void)
{
int n;
long long ans1, ans2;
while (~scanf("%d", &n))
{
for (int i = ; i < n; i++)
{
scanf("%d", &road[i]);
new_road[i] = road[i];
}
qsort(new_road, n, sizeof(int), fcmop1);
ans1 = Search_Increase(n);
printf("%lld", ans1);
/*
这题有问题,只用求不下降序列就可以了,如果求不上升序列会出错
qsort(new_road, n, sizeof(int), fcmop2);
ans2 = Search_Decrease(n);
printf("%lld\n", min(ans1, ans2));
*/
} return ;
} long long Search_Increase(const int n)
{
memset(dp1, , sizeof(dp1));
memset(dp2, , sizeof(dp2)); long long min_tmp, *dp_tmp = NULL, *p1 = dp1, *p2 = dp2, ans; for (int i = ; i < n; i++)
{
min_tmp = p1[];
for (int j = ; j < n; j++)
{
min_tmp = min(min_tmp, p1[j]);
p2[j] = (ABS(road[i], new_road[j])) + min_tmp;
}
dp_tmp = p1; p1 = p2; p2 = dp_tmp;
}
ans = p1[];
for (int i = ; i < n; i++)
ans = min(ans, p1[i]);
return ans;
} long long Search_Decrease(const int n)
{
memset(dp1, , sizeof(dp1));
memset(dp2, , sizeof(dp2)); long long min_tmp, *dp_tmp = NULL, *p1 = dp1, *p2 = dp2, ans; for (int i = ; i < n; i++)
{
min_tmp = p1[];
for (int j = ; j < n; j++)
{
min_tmp = min(min_tmp, p1[j]);
p2[j] = ABS(road[i], new_road[j]) + min_tmp;
}
dp_tmp = p1; p1 = p2; p2 = dp_tmp;
}
ans = p1[];
for (int i = ; i < n; i++)
ans = min(ans, p1[i]);
return ans;
}
另外这一题有BUG,那就是只用找不下降序列就可以了,两个都找会出错。。。。。
DP:Making the Grade(POJ 3666)的更多相关文章
- S - Making the Grade POJ - 3666 结论 将严格递减转化成非严格的
S - Making the Grade POJ - 3666 这个题目要求把一个给定的序列变成递增或者递减序列的最小代价. 这个是一个dp,对于这个dp的定义我觉得不是很好想,如果第一次碰到的话. ...
- A-Making the Grade(POJ 3666)
Making the Grade Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4656 Accepted: 2206 ...
- Making the Grade POJ - 3666
A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would l ...
- Poj 3666 Making the Grade (排序+dp)
题目链接: Poj 3666 Making the Grade 题目描述: 给出一组数,每个数代表当前位置的地面高度,问把路径修成非递增或者非递减,需要花费的最小代价? 解题思路: 对于修好的路径的每 ...
- 「POJ 3666」Making the Grade 题解(两种做法)
0前言 感谢yxy童鞋的dp及暴力做法! 1 算法标签 优先队列.dp动态规划+滚动数组优化 2 题目难度 提高/提高+ CF rating:2300 3 题面 「POJ 3666」Making th ...
- 把一个序列转换成非严格递增序列的最小花费 POJ 3666
//把一个序列转换成非严格递增序列的最小花费 POJ 3666 //dp[i][j]:把第i个数转成第j小的数,最小花费 #include <iostream> #include < ...
- POJ - 3666 Making the Grade(dp+离散化)
Description A straight dirt road connects two fields on FJ's farm, but it changes elevation more tha ...
- POJ 3666 Making the Grade(数列变成非降序/非升序数组的最小代价,dp)
传送门: http://poj.org/problem?id=3666 Making the Grade Time Limit: 1000MS Memory Limit: 65536K Total ...
- POJ 3666 Making the Grade(二维DP)
题目链接:http://poj.org/problem?id=3666 题目大意:给出长度为n的整数数列,每次可以将一个数加1或者减1,最少要多少次可以将其变成单调不降或者单调不增(题目BUG,只能求 ...
随机推荐
- 【FE前端学习】第二阶段任务-基础
技能学习部分: 1.需要熟练掌握HTML标签以及CSS各个常用属性. 2.掌握CSS3 常用属性 3.掌握jquery的基本用法,对于JS基本逻辑语句需要熟练掌握 上文 [FE前端学习]第二阶段任务- ...
- python 类型之 set
python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和 ...
- BZOJ-1206 虚拟内存 Hash+离散化+Priority_Queue
闻说HNOI每年都有一道Hash. 1206: [HNOI2005]虚拟内存 Time Limit: 50 Sec Memory Limit: 162 MB Submit: 330 Solved: 2 ...
- SQLServer用sql语句怎么返回一个月所有的天数
可用如下sql语句: select convert(varchar(10),dateadd(DAY,t2.number,t1.day),120) day from (select '2015-07'+ ...
- linux 搭建SVN服务器,为多个项目分别建立版本库并单独配置权限
1.安装svn服务 # yum install subversion 2.新建一个目录用于存储SVN所有文件 # mkdir /home/svn 3.在上面创建的文件夹中为项目 p ...
- 一段代码了解Java中char和int的转换
题目要求: 将输入的大写字母转成对应小写的后5个,如A转换后为f:如果转换后大于z则从a重新计,即多出1就转成a,多出2就转成b以此类推. Java代码: ```java private static ...
- explicit构造函数
explicit构造函数 Explicit Constructors(显式构造函数)收藏 按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面 ...
- C++中map的基本操作和使用;
注:本文来自sina live 的博文 Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!1. map最基本 ...
- Web SQL数据库
Web SQL数据库:它是一个独立的规范,引入了一组使用SQL操作客户端数据库的API. openDatabase方法:这个方法使用现有的数据库或者新建的数据库创建一个数据库对象.如果数据库存在,op ...
- LDA(Linear discriminate analysis)线性判别分析
LDA 线性判别分析与Fisher算法完全不同 LDA是基于最小错误贝叶斯决策规则的. 在EMG肌电信号分析中,... 未完待续:.....