HDU-1051 Wooden Sticks--线性动归(LIS)

题目大意:有n根木棍(n<5000),每根木棍有一个长度l和重量w(l,w<10000),现在要对这些木头进行加工,加工有以下规则:

    1.你需要1分钟来准备第一根木头。

    2.如果下一根木头比第一根长且重,那么不需准备时间即可加工,否则需要1分钟时间准备。

木头没有顺序,求最小时间代价。(有多组数据)

输入:第一行t:需要处理的组数,接下来有t组数据,每组第一行是n,表示木头个数,下一行是n组,每组两个数,表示第i块木头的长、重。

  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 

输出:

  2
  1
  3(注意换行!!!!!!)

题目分析:一个典型LIS板子题,因为有两个限制条件,所以可以先排序其中一个条件,对另一个条件进行LIS求最少划分数。

      我们可以这么想:现在这些木头已经按长度从小到大排好序了,只要后面一根木头比前面轻,那么代价就+1,所以我们要求最少代价,就是最少划分数,                         划分的依据就是:后一个比前一个木头重,就可以合并,反之则划分数+1。

以下是代码:

 #include<cstdio>#include<cstring>#include<iostream>

#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int n;

struct ll{
    int l,w;//定义结构体变量保存长度和重量,便于排序。
}lw[maxn];

int c[maxn];
int Max=1; //Max不要设为0,答案最小是1(根据第一条规则) 
bool cmp(ll a,ll b){
if(a.l==b.l) return a.w>b.w;
return a.l<b.l;
}
void LIS(){//题目范围是5000,O(n^2)的效率足矣 for(int i=1;i<=n;i++){ c[i]=1; for(int j=1;j<i;j++){ if(lw[i].w<lw[j].w&&c[i]<c[j]+1){//lw[i].w<lw[j].w是lw[i].w>=lw[j].w的反链 c[i]=c[j]+1; Max=max(Max,c[i]); }//最长反链等于最小正链划分数(证明自己百度) //通过求出最长反链的长度即可求得最少代价 } } printf("%d\n",Max); } void clear(){ memset(c,1,sizeof(c)); for(int i=1;i<=n;i++){ lw[i].w=lw[i].l=0; } Max=1; }//多组数据的初始化 int main(){ int t; scanf("%d",&t); for(int i=1;i<=t;i++){ scanf("%d",&n); for(int j=1;j<=n;j++){ scanf("%d%d",&lw[j].l,&lw[j].w); } //读入数据 sort(lw+1,lw+n+1,cmp);//对长度进行排序,对重量LIS LIS(); clear(); } return 0; }

代码就是这样,其中LIS的思想还是很重要的。

 

posted @ 2020-04-06 23:00  刘益通  阅读(121)  评论(0编辑  收藏  举报