最长上升子序列(LIS)POJ 1631 Bridging Signals

POJ 1631题目大意如下:

给定N个测试,每个测试的数据:第一行输入P,表示有P个连接,接下来的P个数据是按照下标从1到P排列的,每个下标i对应一个连接数a[i],表示i和a[i]是连接的,生动点就如下图所示,问题要求给出一个数字,表示的是在这P个连接数里,没有互相交叉的最大组合数。



从上图看的话,其实只是有助于理解题目意思,但是要解决问题的话,这个图还是会带来干扰。肯定不可以直接去模拟,所以我把测试的P个数据按照下标数排列出来,一下发现问题原来如此:就是一个最长上升子序列问题(LIS)。由于一边在学习《挑战程序设计竞赛》这本书,所以问题一下就得到解决的算法。

由于不能有信号线的交叉,那么比如之前的一个下标i对应了a[i],那么之后的下标j能够对应的连接值一定要比a[i]大,所以这么看来就是求一个序列的最大上升子序列。使用DP,但是定义DP数组的方式有两种,第一种肯定会超时,第二种通过,这里两种方法都写下来吧:

1.定义数组dp[i]:表示以a[i]结尾的最大上升子序列的长度。

既然是这样定义,那么每次对于一个新的dp[i],都要检查之前的a[j],如果出现a[j] < a[i]那么使用这个dp[j]去更新dp[i],表达式为:

dp[i] = max{dp[j] + 1| a[j] < a[i] & 1 <= j <= i}

以下是代码:

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;
const int maxn = 40000;
int a[maxn + 1];

int N, P;
int dp[maxn + 1];

void solve() {
	int ans = 0;
	fill(dp, dp + 1 + P, 1);
	dp[1] = 1;
	for (int i = 1; i <= P; i++) {
		for (int j = 1; j < i; j++) {
			if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1); 
		}
		ans = max(ans, dp[i]);
	}
	printf("%d\n", ans);
}

int main() {
	scanf("%d", &N);
	while (N--) {
		scanf("%d", &P);
		for (int i = 1; i <= P; i++) scanf("%d", &a[i]);
		solve();
	}
	return 0;
}

2.定义dp[i]:表示长度为 i + 1的上升子序列的末尾元素最小值,如果没有的话就是INF

为什么这样定义?从之前定义的角度来看,如果这个上升序列的末尾元素值越小,那么对于之后的求解则更加有利。实际使用的话,可以通过更新一个有序的dp就好,最后找到对后一个不是INF的dp下标就代表了最长长度,代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int maxn = 40000;
const int INF = 100000;
int a[maxn + 1];

int N, P;
int dp[maxn + 1];

void solve() {
	fill(dp, dp + P, INF);
	for (int i = 0; i < P; i++)
		*lower_bound(dp, dp + P, a[i]) = a[i];
	printf("%ld\n", lower_bound(dp, dp + P, INF) - dp);
}

int main() {
	scanf("%d", &N);
	while (N--) {
		scanf("%d", &P);
		for (int i = 0; i < P; i++) scanf("%d", &a[i]);
		solve();
	}
	return 0;
}

Accept 996K/125MS

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值