这个题是一开始学贪心的时候刷的,思路是先排个序,按照l,然后找w有多少个上升序列
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 5005;
struct node
{
int l,w;
};
node a[maxn];
int vis[maxn];
bool cmp(node a1,node a2)
{
if(a1.l!=a2.l) return a1.l<a2.l;
else return a1.w<a2.w;
}
void solve(int now,int n)
{
int L=a[now].l,W=a[now].w;
for(int i=now+1;i<n;i++)
{
if(a[i].l>=L&&a[i].w>=W&&!vis[i])
{
vis[i]=1;
L=a[i].l,W=a[i].w;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
cin>>a[i].l>>a[i].w;
sort(a,a+n,cmp);
int time=0;
for(int i=0;i<n;i++)
{
if(!vis[i])
{
time++;
vis[i]=1;
solve(i,n);
}
}
printf("%d\n",time);
}
return 0;
}
参考http://www.hankcs.com/program/cpp/poj-1065-wooden-sticks.html
然后其实是求w的最长下降子序列,和LIS的方法一样,条件改下就好了
dp[i]:以a[i]结尾的最长下降子序列的长度
时间复杂度为O(n*n),还是比较大,不过这道题因为n比较小,到5000,时间enough
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 5005;
struct node
{
int l,w;
};
node a[maxn];
int dp[maxn];
int vis[maxn];
bool cmp(node a1,node a2)
{
if(a1.l!=a2.l) return a1.l<a2.l;
else return a1.w<a2.w;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&a[i].l,&a[i].w);
sort(a+1,a+n+1,cmp);
int time=0;
for(int i=1;i<=n;i++)
{
for(int j=i-1;j>=1;j--)
{
if(a[j].w>a[i].w) dp[i]=max(dp[i],dp[j]+1);
}
time=max(dp[i],time);
}
printf("%d\n",time+1);
}
return 0;
}
我们还可以优化一下
dp[i]:长度为i个最长递减序列的最大尾元素,这样的话,时间复杂度为O(nlogn)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 5005;
struct node
{
int l,w;
};
node a[maxn];
int dp[maxn];
int vis[maxn];
bool cmp(node a1,node a2)
{
if(a1.l!=a2.l) return a1.l<a2.l;
else return a1.w<a2.w;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&a[i].l,&a[i].w);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
int l=1,r=n,res=r;
while(l<=r)
{
int mid=l+(r-l)/2;
if(dp[mid]>a[i].w) l=mid+1;
else {res=mid;r=mid-1;}
}
dp[res]=max(a[i].w,dp[res]);
}
for(int i=1;i<=maxn;i++)
if(dp[i]==0) {printf("%d\n",i-1);break;}
}
return 0;
}