poj1065(dilworth定理+lis)

点击打开链接

/*
translation:
	n根木材长l_i重w_i,前一根木材大于后一根的话要浪费一分钟准备机器,求最省方案?
	
solution:
	dp, dilworth定理, lis
	此道题是求按照某一元素(长度或者重量)排序后,另一种元素最少有几个上升子序列?
	这样就可以通过求另一种元素的最长下降子序列的长度,就是上升子序列的最少个数。--dilworth定理
	
note:
	dilworth定理:
	定理1 令(X,≤)是一个有限偏序集,并令r是其最大链的大小。则X可以被划分成r个但不能再少的反链。 
	其对偶定理称为Dilworth定理:
	定理2 令(X,≤)是一个有限偏序集,并令m是反链的最大的大小。则X可以被划分成m个但不能再少的链。
	证明:设p为最少反链个数
      (1)先证明X不能划分成小于r个反链。由于r是最大链C的大小,C中任两个元素都可比,因此C中任两个
      元素都不能属于同一反链。所以p>=r。
      (2)设X1=X,A1是X1中的极小元的集合。从X1中删除A1得到X2。注意到对于X2中任意元素a2,必存
      在X1中的元素a1,使得a1<=a2。令A2是X2中极小元的集合,从X2中删除A2得到X3……最终,会有一个
      Xk非空而X(k+1)为空。于是A1,A2,...,Ak就是X的反链的划分,同时存在链a1<=a2<=...<=ak,其
      中ai在Ai内。由于r是最长链大小,因此r>=k。由于X被划分成了k个反链,因此r>=k>=p。因此r=p,定理1得证。
      
date:
	2016.9.12
*/
#include 
#include 
#include 
#include 

using namespace std;
const int maxn = 10000 + 5;

struct Stick {
	int l, w;	//长度和重量
	Stick(int l_, int w_) : l(l_), w(w_) {}
	Stick() {}
	bool operator < (const Stick& rhs) const {
		if(l == rhs.l)	return w < rhs.w;
		else			return l < rhs.l;
	}
} sticks[maxn];
int n;
int d[maxn];

int main()
{
	//freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--) {
		scanf("%d", &n);
		for(int i = 0; i < n; i++)
			scanf("%d%d", &sticks[i].l, &sticks[i].w);

		sort(sticks, sticks + n);
		memset(d, 0, sizeof(d));

		int ans = 0;
		for(int i = 0; i < n; i++) {
			d[i] = 1;
			for(int j = 0; j < i; j++) {
				if(sticks[j].w > sticks[i].w)
					d[i] = max(d[i], d[j] + 1);
			}
			ans = max(ans, d[i]);
		}

		printf("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(=====动态规划=====,基本dp)