摆木棍

  题目大意:即使有一堆木棍,给一个特殊机器加工,木棍都有两个属性,一个是l一个是w,当机器启动的时候(加工第一根木棒的时候),需要一分钟,在这以后,设机器加工的上一根木棒的长度是l,质量是w,下一次加工的木棒长度为l`,质量为w`,当且仅当l`>=l且w`>=w时,机器不需要额外的时间,否则还需要一分钟重新启动,问你最短的加工时间?

  下面介绍两个方法:

  方法一,直接贪心法:

  这个方法的原理是:因为我们总是想把更多的木棍按序排列,所以我们可以先把一个属性先排列了,再考虑另一个属性,那么这样的话假设我们先排序l,那么的话我们就只用看w就可以了,但是在我第一次想的时候我犯了一个很严重的错误,那就是我把w也按照升序来操作了(而没有跟新当前最大质量),实际上我们还要更新stick的最大质量,这样才能行(当然要used域了)

  还要注意的是排序的时候当l相等的时候,w记得按照升序排

  代码太简单了,我不贴了,反正这算法跑挺慢的,我写的跑47ms,没啥意思,我们来点有意思的方法。

  方法二:LIS(最长下降子序列)

  在扯这个方法之前,我们先来讲一下组合数学的东西:偏序集和Dilworth定理

  偏序集的定义:

  设一个集合P,里面满足关系R,设xRy表示x与y满足R相关,x!Ry表示x与y不相关

  1.如果对于X中的所有元素x,都有x与x满足R的关系,那么则说明R是自反的

  2.如果对于X中的所有元素x,都不满足R的关系(x!Rx),那么说明R是反自反的。

  3.如果对于X所有的x和y,都有xRy,x!Ry,则说明R是反对称的,否则如果xRy和xRy成立时,x!=y则说明R是对称的

  4.如果X所有元素xyz,满足xRy,yRz,如果一定存在xRz,则说明R是传递的

  偏序集就是一个自反,反对称且传递的关系,偏序是一种关系(比如集合的包含,大于小于都是偏序,特别的,一切不带等号的偏序都是严格偏序)

  现在我们直接用偏序集的定理(不证),详细证明方法看维基百科https://en.wikipedia.org/wiki/Dilworth%27s_theorem

  

  偏序集的定理1:

  令(X,≤)是一个有限偏序集,并令r是其最大链的大小。则X可以被划分成r个但不能再少的反链。

  偏序集的定理2:(DilWorth定理)

  令(X,≤)是一个有限偏序集,并令m是反链的最大的大小。则X可以被划分成m个但不能再少的链。

  也就是链的最小化划分数=反链的最大长度

  参考http://blog.csdn.net/xuzengqiang/article/details/7266034

  

  那么说到这里,你就明白了,这一题其实就是最著名的LIS(只不过他是要求反链)

  LIS有两个解法,各有优劣,第一个解法虽然是O(n^2),但是可以显示出所有的链长和回溯显示链

  第一个解法其实就是DP,我们从头到尾搜索数组,不断更新当前位置的最长长度(当然这个要满足下降关系),然后找出最长的链就可以了,很简单

  

 #include <iostream>
#include <functional>
#include <algorithm> using namespace std;
typedef struct woods_
{
int length;
int weight; }WOODS;
typedef int Position;
int fcomp(const void *a, const void *b)
{
if ((*(WOODS *)a).length != (*(WOODS *)b).length)
return (*(WOODS *)a).length - (*(WOODS *)b).length;
else
return (*(WOODS *)a).weight - (*(WOODS *)b).weight;
} static WOODS woods_set[];
static int dp[]; void Search(const int); int main(void)
{
int case_sum, woods_sum;
scanf("%d", &case_sum);
for (int i = ; i < case_sum; i++)
{
scanf("%d", &woods_sum);
for (int j = ; j < woods_sum; j++)
scanf("%d%d", &woods_set[j].length, &woods_set[j].weight); qsort(woods_set, woods_sum, sizeof(WOODS), fcomp);
memset(dp, , sizeof(dp));
if (woods_sum == )
printf("0\n");
else Search(woods_sum);
}
return ;
} void Search(const int woods_sum)
{
int ans = ; dp[] = ;
for (int i = ; i < woods_sum; i++)
{
dp[i] = ;
for (int j = ; j < i; j++)
{
if (woods_set[j].weight > woods_set[i].weight)
dp[i] = max(dp[j] + , dp[i]);
}
}
ans = ;
for (int i = ; i < woods_sum; i++)
ans = max(ans, dp[i]);
printf("%d\n", ans);
}

  第二个方法是O(nlogn),这个很快,原理就是我们的最长连储存就可以了,然后用二分的方法更新元素,并且用贪婪的方法,不断更新stacks里面的元素(比如我们按照从大到小排,那么不断更新最大就可以了),让链的增长潜能变大!这个方法的缺点就是不能显示链(显示的也是错的),而且只能找最长的那一条。

  不过为什么这个算法能成立也是很有趣的,因为我们一直在更新元素,但是最后的链的序不一定就是原来的序,其实内在的原因就是这个方法把每一个元素都等价了,其实不管我们怎么找,如果我们只用找最长的话,那么其实我们只用把潜力变大?(下降链找最大元素,上升链找最小元素),那么这样的链的长度最后一定是最大的

  代码:

  

 #include <iostream>
#include <functional>
#include <algorithm> using namespace std;
typedef struct woods_
{
int length;
int weight; }WOODS;
typedef int Position;
int fcomp(const void *a, const void *b)
{
if ((*(WOODS *)a).length != (*(WOODS *)b).length)
return (*(WOODS *)a).length - (*(WOODS *)b).length;
else
return (*(WOODS *)a).weight - (*(WOODS *)b).weight;
} static WOODS woods_set[];
static int stacks[]; void Search(const int);
Position Binary_Search(const int,int,int,const int len); int main(void)
{
int case_sum, woods_sum;
scanf("%d", &case_sum);
for (int i = ; i < case_sum; i++)
{
scanf("%d", &woods_sum);
for (int j = ; j < woods_sum; j++)
scanf("%d%d", &woods_set[j].length, &woods_set[j].weight); qsort(woods_set, woods_sum, sizeof(WOODS), fcomp);
//memset(stacks, -1, sizeof(stacks));
if (woods_sum == )
printf("0\n");
else Search(woods_sum);
}
return ;
} Position Binary_Search(const int goal, int left, int right, const int len)
{
int mid; while (left <= right && left != len)//二分法维护序列
{
mid = (left + right) / ;
if (goal < stacks[mid])
left = mid + ;
else
right = mid - ;
}
return left;
} void Search(const int woods_sum)
{
int pos, len = ; stacks[] = -;
for (int i = ; i < woods_sum; ++i)
{
pos = Binary_Search(woods_set[i].weight, , len, len); stacks[pos] = woods_set[i].weight;
if (pos == len)
len++;
}
printf("%d\n", len);
}

  

DP:Wooden Sticks(POJ 1065)的更多相关文章

  1. POJ 1065 Wooden Sticks / hdu 1257 最少拦截系统 DP 贪心

    参考链接:http://blog.csdn.net/xiaohuan1991/article/details/6956629 (HDU 1257 解题思路一样就不继续讲解) POJ 1065题意:给你 ...

  2. POJ 1065 Wooden Sticks

    Wooden Sticks Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 16262 Accepted: 6748 Descri ...

  3. HDU ACM 1051/ POJ 1065 Wooden Sticks

    Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  4. POJ 1065 Wooden Sticks (贪心)

    There is a pile of n wooden sticks. The length and weight of each stick are known in advance. The st ...

  5. Wooden Sticks(hdu1501)(sort,dp)

    Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  6. HDU 1051 Wooden Sticks 贪心||DP

    Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  7. 【例题收藏】◇例题·IV◇ Wooden Sticks

    ◇例题·IV◇ Wooden Sticks 借鉴了一下 Candy? 大佬的思路 +传送门+ (=^-ω-^=) 来源:+POJ 1065+ ◆ 题目大意 有n个木棍以及一台处理木棍的机器.第i个木棍 ...

  8. Wooden Sticks(贪心)

    Wooden Sticks. win the wooden spoon:成为末名. 题目地址:http://poj.org/problem?id=1065 There is a pile of n w ...

  9. HDU1051 Wooden Sticks 【贪婪】

    Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

随机推荐

  1. BZOJ-1227 虔诚的墓主人 树状数组+离散化+组合数学

    1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec Memory Limit: 259 MB Submit: 914 Solved: 431 [Submit][Statu ...

  2. 如果您想省略JS里的分号,了解一下JS的分号插入原理吧

    仅在}之前.一个或多个换行之后和程序输入的结尾被插入 也就是说你只能在一行.一个代码块和一段程序结束的地方省略分号. 也就是说你可以写如下代码 function square(x) { var n = ...

  3. resharper安装后,一不小心点错了(选择了object browser)

    打开Resharper,选择Options,然后选择Tools中的External Sources,你的情况是选择了Navigation to Object Brower这一项了,换成第一个Defau ...

  4. redis设置密码和主从复制

    redis设置连接密码: 因为redis的速度相当的快,在一台比较好的服务器下,每秒可进行150K次密码尝试,所以要设置个非常强大的密码. 设置方式:修改配置文件redis.conf #require ...

  5. pom.xml

    使用intelJ idea 导入maven包管理文件是,使用Import的方式导入,会自动导入pom.xml来导入包. pom.xml会指定父子关系. 例如,总模块的pom.xml中有一下内容: &l ...

  6. FreeMarker template error!

    部署项目后发现以下“FreeMarker template error!”的问题,google.baidu猛一顿搜索无果后开始认真分析异常信息. FreeMarker template error! ...

  7. mysqli 操作数据库(转)

    从php5.0开始增加mysql(i)支持 , 新加的功能都以对象的形式添加 i表示改进的意思 功能多.效率高.稳定 编译时参数: ./configure --with-mysql=/usr/bin/ ...

  8. ios开发@selector的函数如何传参数/如何传递多个参数

    不同的类会有不同的传递方式,参数名也不尽相同.如果是传单个参数的就不用集合,如果是传多个参数可以用类似nsarray,nsdictionary之类的集合传递.看下面例子: 例子1: 通过NSTimer ...

  9. c#之Redis实践list,hashtable

    写在前面 最近公司搞了一个活动,用到了redis的队列,就研究了下redis的相关内容.也顺手做了个demo. C#之使用Redis 可以通过Nuget安装Reidis的相关程序集.安装之后发现会引入 ...

  10. angular-ngSanitize模块-linky过滤器详解

    本篇主要讲解angular中的linky这个过滤器.此过滤器依赖于ngSanitize模块. linky能找出文本中的链接,然后把它转换成html链接.什么意思,就是说,一段文本里有一个链接,但是这个 ...