在做题的时候无意中做到了这方面的题,这个是离散中的一个知识点
我觉得和贪心区别不大
说到偏序集,在离散里的定义是:
设R为非空集合A上的关系,如果R是自反的、反对称的和传递的,则称R为A上的偏序关系,简称偏序,记作≤。
偏序是在集合X上的二元关系≤(这只是个抽象符号,不是“小于或等于”),它满足自反性、反对称性和传递性。即,对于X中的任意元素a,b和c,有:
自反性:a≤a;
反对称性:如果a≤b且b≤a,则有a=b;
传递性:如果a≤b且b≤c,则a≤c 。
带有偏序关系的集合称为偏序集。
令(X,≤)是一个偏序集,对于集合中的两个元素a、b,如果有a≤b或者b≤a,则称a和b是可比的,否则a和b不可比。
在X中,对于元素a,如果任意元素b,由b≤a得出b=a,则称a为极小元。
一个反链A是X的一个子集,它的任意两个元素都不能进行比较。
一个链C是X的一个子集,它的任意两个元素都可比。
任何集合A上的恒等关系,集合的幂集P(A)上的包含关系,实数集上的小于等于关系,正整数集上的整除关系等都是偏序关系。
那么现在,我们重点利用集合的包含关系来解决poj1065、poj3636这两题。
POJ1065 题意:有n个木棒,分别不同的长度和不同的重量,一个机器需要处理这些木棒,如果第i+1个木棒的重量和长度都>=第i个处理的木棒,那么将不会耗费时间,否则需要增加一个单位的时间,问最少需要多少时间处理完(包括机器启动的时间)。
POJ3636 题意:套娃娃,只有当 w1 < w2 && h1 < h2 时才能将娃娃(w1,h1)套在娃娃(w2,h2)里面,问最少需要多少嵌套的娃娃。
算法:二者区别在于前者是大于等于关系,而后者必须是大于的。这就导致了二者排序的方式不一样,第一个参数都是从小到大排,但是第二个参数就有所区别了。前者要求是包含 =的,所以第2个参数也是从小到大排;而后者则不包含 = 所以要从大到小排 。因为w升序,h降序可以保证w相等时,一定不会出现覆盖的情形。
其实还有一个解决方案就是按最长非升子序列来写,这个以后做到在介绍
poj 1065
#include<stdio.h>
#include<algorithm>
using namespace std;
#define Max 5005
struct node{
int l,w;
}n[Max];
int an[Max];
bool cmp(node x,node y)
{
if(x.w==y.w) return x.l<y.l;
return x.w<y.w;
}
int main()
{
int t,m,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&m);
for(i=0;i<m;i++)
scanf("%d%d",&n[i].l,&n[i].w);
sort(n,n+m,cmp);
int num=0;
for(i=0;i<m;i++)
{
int flag=0;
for(j=0;j<num;j++)
if(n[i].l>=an[j])
{
an[j]=n[i].l;
flag=1;
break;
}
if(!flag) an[num++]=n[i].l;
}
printf("%d\n",num);
}
return 0;
}
poj 3636(这个好像可以用二分图匹配来做,到时再在二分图专题写一写)
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
const int maxn = 20000 + 100;
struct node{
int w,h;
};
node d[maxn],dd[maxn];
bool cmp(node a,node b){
if(a.w==b.w)return a.h>b.h;
return a.w<b.w;
}
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&d[i].w,&d[i].h);
}
sort(d,d+n,cmp);
int tmp=0;
for(int i=0;i<n;i++){
int mark=0;
for(int j=0;j<tmp;j++){
if(d[i].w>dd[j].w&&d[i].h>dd[j].h){
dd[j]=d[i];
mark=1;
break;
}
}
if(!mark){
dd[tmp++]=d[i];
}
}
printf("%d\n",tmp);
}
}