Bridging signals(最长上升子序列)

Bridging signals

题目

“哦,不,他们又做到了”,Waferland 芯片厂的首席设计师喊道。布线设计人员再次完全搞砸了,使连接两个功能块端口的芯片上的信号到处都是相互交叉的。在这个过程的后期阶段,重做路由的成本太高了。相反,工程师必须使用第三维来桥接信号,以免两个信号交叉。然而,桥接是一个复杂的操作,因此希望桥接尽可能少的信号。迫切需要一种计算机程序,以找到可以在硅表面上连接而不相互交叉的最大数量的信号。记住在功能块的边界处可能有数千个信号端口,这个问题对程序员提出了很多要求。你能胜任这项任务吗?

图 1 示意性地描绘了一种典型情况。两个功能块的端口从 1 到 p,从上到下编号。信号映射由数字 1 到 p 以范围 1 到 p 中的 p 个唯一数字的列表的形式进行描述,其中第 i 个数字指定右侧的哪个端口应连接到i:左侧的第一个端口。当且仅当连接每对两个端口的直线交叉时,两个信号交叉。
在这里插入图片描述

思路

  • 将相交翻译为数学语言即 a [ i ] > a [ j ] a[i] > a[j] a[i]>a[j] 其中 a [ i ] a[i] a[i] 表示第 i i i 个位置的链接点编号.
    为不相交即保持 a [ i ] < a [ j ] ( i < j ) a[i]<a[j] (i<j) a[i]<a[j](i<j) ,所以很明显发现这是一个最长上升子序列问题(LIS)
  • 由于数据规模 40000 40000 40000 ,因此 O ( n ∗ n ) O(n*n) O(nn) 的算法无法解决, 选用 O ( n l o g n ) O(nlogn) O(nlogn)算法解决.

DP算法 O ( n ∗ n ) O(n*n) O(nn)

  • 定义 d p [ i ] dp[i] dp[i] 是以i为结尾的上升子序列.

  • 状态转移一定从 d p [ 1 , i − 1 ] dp[1 , i-1] dp[1,i1]+1的最大值

    即: d p [ i ] = m a x ( d p [ 1 , j ] ) + 1 dp[i] = max(dp[1,j])+1 dp[i]=max(dp[1,j])+1 ( a [ i ] > a [ j ] 且 j < i ) (a[i]>a[j]且j<i) (a[i]>a[j]j<i)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<fstream>
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 4e4 ,mod=1e9 + 7;
int dp[N];
int n;
int a[N];
void solve()
{    
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	memset(dp,0,sizeof dp);
	for(int i=2;i<=n;i++)// O(n^2)
	{
		dp[i] = 1;
		for(int j=i-1;j>=1;j--)
			if(a[i]>a[j]) dp[i] = max(dp[i],dp[j] + 1);
	}
	int res=0;
	for(int i=1;i<=n;i++) res = max(res,dp[i]);
	cout << res <<endl;
}
signed main()
{
	ios::sync_with_stdio();cin.tie();cout.tie();

	int T;cin>>T;
	while(T--)
		solve();

	//cerr<<endl<<" Time : "<< T2-T1 <<"ms."<<endl; 
	return 0;
}

显然该算法无法解决本题.


贪心+二分 O ( n ∗ l o g n ) O(n*logn) O(nlogn)

  • 我们维护一个记录升序序列长为 i i i时最小末尾值的数组 l i s [ n ] lis[n] lis[n].
    这个数组的最大长度即为所求

  • 关于此算法的正确性不会很严谨的证明
    暂时感性认为,末尾越小越有利于之后构成最长上升序列.

  • 因为维护过程中总是在查找 a [ i ] a[i] a[i]的替换位置,该数列又是有序的,因此可以用二分优化.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<fstream>
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 4e4 ,mod=1e9 + 7;
int dp[N];
int n;
int a[N];
void solve()
{    
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",a+i);
	vector<int>lis(n);
	{
		for(int i=0;i<n;i++)lis[i] = inf;
	}

	for(int i=1;i<=n;i++)
	{
		int p = lower_bound(lis.begin(),lis.end(),a[i]) - lis.begin();
		lis[p] = a[i];
	}
	printf("%d\n",lower_bound(lis.begin(),lis.end(),inf) - lis.begin());
}
signed main()
{
	// ios::sync_with_stdio();cin.tie();cout.tie();

	int T;cin>>T;
	while(T--)
		solve();

	//cerr<<endl<<" Time : "<< T2-T1 <<"ms."<<endl; 
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值