HDU 3165 Trainsorting (DP, LIS)

Trainsorting

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 436    Accepted Submission(s): 124


Problem Description
Erin is an engineer. She drives trains. She also arranges the cars within each train. She prefers to put the cars in decreasing order of weight, with the heaviest car at the front of the train.

Unfortunately, sorting train cars is not easy. One cannot simply pick up a car and place it somewhere else. It is impractical to insert a car within an existing train. A car may only be added to the beginning and end of the train.

Cars arrive at the train station in a predetermined order. When each car arrives, Erin can add it to the beginning or end of her train, or refuse to add it at all. The resulting train should be as long as possible, but the cars within it must be ordered by weight. 

Given the weights of the cars in the order in which they arrive, what is the longest train that Erin can make?
 

Input
The first line contains an integer 0 <= n <= 2000, the number of cars. Each of the following n lines contains a non-negative integer giving the weight of a car. No two cars have the same weight.
 

Output
Output a single integer giving the number of cars in the longest train that can be made with the given restrictions.
 

Sample Input
  
  
3 1 2 3
 

Sample Output
  
  
3
 

题意:每次来一辆车,可以让它留下,也可以让它走,如果要留下的话,要根据重量,整个车队依次递减,这辆车只能插在车队前面或车队后面。求这个车队最长为多少。

思路:设第i辆为第一辆留下的车,ans = LIS[i] + LDS[i] - 1。若以每节车厢为第一辆停留的车,求一遍LIS以及LDS,这样时间复杂度变成了n^2logn,显然不可行。这时候我们可以采用逆序的方式dp,把最后一个数当作起点,如果求LIS,则dp[i]就是从a[n]--->a[i]的LIS,也是a[i]--->a[n]的LDS,这样就巧妙地减少了时间复杂度。

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int a[2005], LIS[2005], LDS[2005];
int solve(int n){
	int i, j, ans = 0; 
	//逆序DP求最长单调递增/递减子序列 
	for(i = n; i >= 1; i--){
		LIS[i] = LDS[i] = 1;//赋初始值 
		for(j = n; j > i; j--){
			if(a[i] > a[j]){
				//LDS[i]是针对顺序情况下的递减子序列,在逆序情况下就是递增 
				LDS[i] = max(LDS[i], LDS[j] + 1);
			} else {
				LIS[i] = max(LIS[i], LIS[j] + 1);
			}
		}
		//最大长度即LIS+LDS-1,减1是因为a[i]本身多计数了一次。 
		ans = max(ans, LIS[i] + LDS[i] - 1);
	}     
	return ans;
} 
int main(){
	int n, i, j;
	while(scanf("%d", &n) != EOF){//题目上未说明有多组数据,但实际情况却是 
		for(i = 1; i <= n; i++){
			scanf("%d", &a[i]);
		}
		cout<<solve(n)<<endl;
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值