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的思想还是很重要的。