挑战程序设计竞赛2.3:Wooden Sticks POJ - 1065

There is a pile of n wooden sticks. The length and weight of each stick are known in advance. The sticks are to be processed by a woodworking machine in one by one fashion. It needs some time, called setup time, for the machine to prepare processing a stick. The setup times are associated with cleaning operations and changing tools and shapes in the machine. The setup times of the woodworking machine are given as follows:
(a) The setup time for the first wooden stick is 1 minute.
(b) Right after processing a stick of length l and weight w , the machine will need no setup time for a stick of length l‘ and weight w‘ if l <= l‘ and w <= w‘. Otherwise, it will need 1 minute for setup.
You are to find the minimum setup time to process a given pile of n wooden sticks. For example, if you have five sticks whose pairs of length and weight are ( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) , and ( 4 , 1 ) , then the minimum setup time should be 2 minutes since there is a sequence of pairs ( 4 , 1 ) , ( 5 , 3 ) , ( 9 , 4 ) , ( 1 , 2 ) , ( 2 , 5 ) .

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case consists of two lines: The first line has an integer n , 1 <= n <= 5000 , that represents the number of wooden sticks in the test case, and the second line contains 2n positive integers l1 , w1 , l2 , w2 ,..., ln , wn , each of magnitude at most 10000 , where li and wi are the length and weight of the i th wooden stick, respectively. The 2n integers are delimited by one or more spaces.

Output

The output should contain the minimum setup time in minutes, one per line.

Sample Input

3
5
4 9 5 2 2 1 3 5 1 4
3
2 2 1 1 2 2
3
1 3 2 2 3 1

Sample Output

2
1
3这道题看起来束手无策,但是如果你知道组合数学中神奇的狄尔沃斯定理的话,一切就迎刃而解。
狄尔沃斯定理: 对偏序集<A,≤>,设A中最长链的长度是n,则将A中元素分成不相交的反链,反链个数至少是n。

对于反链:设<A>是一个偏序集合,在A的一个子集中,如果每两个元素都是有关系的,则称这个子集为链。在A的一个子集中,如果每两个元素都是无关的,则称这个子集为反链。证明由于鄙人数学垃圾,大家可以去看看百度百科的证明。

题意要求满足对于后面的x,y和前一个x‘,y‘有x >= x‘且 y >= y‘,那么从后往前来看就是一个不上升序列,因此题意是要求我们求得这个最长不上升子序列的最小个数。那么在这里,反链就是最长上升子序列,而最长上升子序列的长度也就是最长不上升子序列的最小个数,也就是我们要求的答案,注意长度和序列个数不一样。

我们可以先排序,因为我们要得到最长上升子序列的长度并且我们要从后往前遍历,就应该按照从小到大排序,对于二维,我们也可以采取排x,这样可以保证,倒序遍历的时候x一定能小于等于之前的,也就是x不会有问题,我们就只要比较y即可。在我们倒序进行排列的时候,我们先把建立一个数组dp(该数组为最长上升序列)初始化为INF,然后把y与最小的大于等于y的值找出(因为等于在上升序列中不会改变序列长度,得要是大于),那么把y与其替换,这样可以使得如此操作后找到最长的上升子序列的个数(也就是数组的个数,因为这样替换使得如果没有比y大的数,那么就会找到INF,将其替换,这样序列的长度就多了一个;如果有比y大的数,保证该数组的原本第一个比y大的值可以变小,但是保持dp的递增的序列不变,如果后面存在现有的序列还大的递增序列,那么就会被替换,这样循环就能找到最长的上升序列。
(结合白书P65仔细想想为什么这样操作就能找到最大上升子序列)

找到了之后就好办了,求出该序列的长度,就能得到最长不上升序列的个数,也是题目要求的答案。AC代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
struct Node{
	int x;
	int y;
	friend bool operator <(Node x, Node y){
		return x.x < y.x;
	}
}sticks[5005];
const int INF= 0x3fffffff;
int dp[5005];
int main(void)
{
	int t, n;
	scanf("%d", &t);
	for(int times = 0; times < t; times++)
	{
		scanf("%d", &n);
		fill(dp, dp + 5005, INF);
		for(int i = 0; i < n; i++)
		{
			scanf("%d %d", &sticks[i].x, &sticks[i].y);
		}
		sort(sticks, sticks + n);
		for(int i = n - 1; i >= 0; i--)
		{
			//lower_bound就是找到在当前序列中第一个大于等于sticks[i].y的位置,它是一个地址减去dp的首地址就得到了该位置的dp数组的下标,实际上这行和下一行可以合并为*lower_bound(dp, dp + n, sticks[i].y) = sticks[i].y的,为了怕指针难看懂就这样写了。
			int p = lower_bound(dp, dp + n, sticks[i].y) - dp;
			dp[p] = sticks[i].y;
		}
		printf("%d\n", lower_bound(dp, dp + n, INF) - dp);//最后最长上升子序列的长度就是最长不上升子序列的最小个数,也就是答案
	}
}

  

 

  



原文地址:https://www.cnblogs.com/jacobfun/p/12234094.html

时间: 2024-08-02 12:01:03

挑战程序设计竞赛2.3:Wooden Sticks POJ - 1065的相关文章

Wooden Sticks POJ - 1065

There is a pile of n wooden sticks. The length and weight of each stick are known in advance. The sticks are to be processed by a woodworking machine in one by one fashion. It needs some time, called setup time, for the machine to prepare processing

Wooden Sticks POJ 1065(简单dp)

原题 题目链接 题目分析 题意很明确,就是要维护单调递增的序列,最后看有多少种单调序列即可,设定一个dp数组,cnt表示数组大小,初始化为0,然后把所有木头从小到大排个序,当遍历到木头i时,如果dp数组里有比木头i还小的,就代替它,否则就dp[cnt++]=木头i,最后cnt就是答案. 代码 1 #include <iostream> 2 #include <algorithm> 3 #include <utility> 4 #include <cstdio>

POJ 3420 Quad Tiling 题解 《挑战程序设计竞赛》

POJ 3420 Quad Tiling贴瓷砖:4*N的地板上用2*1的瓷砖铺满,求所有方案数对M求余.3.4熟练掌握动态规划矩阵的幂久违地上了节课,太无聊,只好刷一题.假设S[n]表示填满n时的方案数,有S[0]=1.定义矩阵M[p][q] := 边缘p和边缘q可以拼合时取1,否则取0所谓的可以拼合表示,两个边缘拼起来后长度为1(为2就拼接不起来了),且内部缝隙可以用2*1的瓷砖填满.那么M就有一些简单的性质了,比如M的第一行应该是:0 0 0 0 0 0... 继续阅读:码农场 » POJ

POJ 3411 Paid Roads 题解 《挑战程序设计竞赛》

POJ 3411 Paid Roads开路:N个城市间有m条单向路,分别从a到b,可以在c处交P路费,也可以直接交R路费.那么问题来了,你的挖掘机怎么开最省钱?3.4熟练掌握动态规划状态压缩DP乍一看可以Dijkstra,实际上的确可以Dijkstra.不过多了一个预交费的c,所以在遍历的时候多了一维状态,这个维度储存当前走过的城市集合.在Dijkstra的时候,如果走过了c那么就有两个选择,选其中最省的即可:否则没得选.#include <iostream> #include&nb.

POJ 2836 Rectangular Covering 题解 《挑战程序设计竞赛》

POJ 2836 Rectangular Covering铺地板:坐标平面上有n各点,用任意大小(非零)的地板砖覆盖它们,求最省的地板砖总面积.3.4熟练掌握动态规划状态压缩DP先预处理数据,将n个点两两组合形成n * (n-1) / 2个矩形,计算每个矩形的面积和内部点个数.接着利用预处理数据来枚举,定义dp[S] := 矩形集为S时的最省面积先假设平面上没有矩形,那么dp[0]=0,接着一个一个地往平面上加矩形,递推关系是:dp[新矩形集合] = min(dp[新矩形集合], dp[旧矩形集

poj2431 Expedition (优先队列) 挑战程序设计竞赛

题目链接:http://poj.org/problem?id=2431 Expedition Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9148   Accepted: 2673 Description A group of cows grabbed a truck and ventured on an expedition deep into the jungle. Being rather poor driver

《挑战程序设计竞赛》课后练习题解集——3.4 熟练掌握动态规划

<挑战程序设计竞赛>课后练习题解集——3.4 熟练掌握动态规划 状态压缩DP POJ 2441  有N头牛,M个槽,N,M≤20,每头牛只在指定的pi个槽里进食,不与其他牛共享槽.问有多少种分配方案. dp[i][S],当前第i头牛要进食,槽的使用状态为S 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespace std; 5 6 int n, m; 7 in

字符串HASH模板 取自挑战程序设计竞赛(第2版)

/*===================================================* 从b串中寻找和a串长度相同的子串,返回开始位置 不保证绝对正确,发生冲突概率为O(sqrt(n)), n为哈希函数的最大值 \*===================================================*/ #define ull unsigned long long const ull B = 1e8+7; /*according to the book*/

[转] AOJ 0525 Osenbei《挑战程序设计竞赛(第2版)》练习题答案

来自 码农场 ? AOJ 0525 Osenbei<挑战程序设计竞赛(第2版)>练习题答案 只把代码复制过来,原博的其他分析请看链接. 1 #include <iostream> 2 #include <bitset> 3 #include <algorithm> 4 5 using namespace std; 6 7 bitset<10000> cookie[10]; 8 9 ///////////////////////////SubMai