题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=236
此题在nyoj上分类中,贪心和dp都有,所以此题两种方法均能做对,我用的贪心,至于贪心为什么成功我也不能给出证明;
首先按长度递增排列,长度相同时按重量递增排列,此题就是要找至少可以划分为多少个单调递增的链,为此构造数组f[i]表示到目前为止第i个链的最后一个木棒的信息,所以每次取出木棒的时候,从前往后扫描f,如果此木棒可以接在f[i]后面,则令f[i]为当前木棒的信息,如果找不到可以接的链,则从新开辟一个链,此时数组f的长度就增加1;最后的结果也就是数组f的长度;
此题还可以用dp做,首先也是按照上面的方法将木棒排列,然后只需要找最长递减子序列就行了,(如果先按长度排则找的是按重量的递减序列),至于为什么正确,这是个偏序集的几个定理,叫做Dilworth定理,有兴趣的可以看下;
贪心参考代码如下:
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
struct tt
{
int l;
int w;
}a[5001],f[5001];
int n;
int comp(const void *x,const void *y)
{
if((*(tt *)x).l>(*(tt *)y).l)
return 1;
if((*(tt *)x).l<(*(tt *)y).l)
return -1;
if((*(tt *)x).w>(*(tt *)y).w)
return 1;
return -1;
}
void execute()
{
memset(f,0,sizeof(f));
int i,j;
int ans=0;
int tag=1;
for(i=0;i<n;i++)
{
tag=1;
for(j=0;j<ans;j++)
{
if(f[j].l<=a[i].l&&f[j].w<=a[i].w)
{
tag=0;
f[j].l=a[i].l;
f[j].w=a[i].w;
break;
}
}
if(tag)
{
f[ans].l=a[i].l;
f[ans].w=a[i].w;
ans++;
}
}
cout<<ans<<endl;
}
int main()
{
int T;
cin>>T;
int i;
while(T--)
{
cin>>n;
for(i=0;i<n;i++)
cin>>a[i].l>>a[i].w;
qsort(a,n,sizeof(a[0]),comp);
execute();
}
return 0;
}