Poj 1631 && Hdu 1950 Bridging signals【LIS】

81 篇文章 0 订阅

Bridging signals

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1077    Accepted Submission(s): 703


Problem Description
'Oh no, they've done it again', cries the chief designer at the Waferland chip factory. Once more the routing designers have screwed up completely, making the signals on the chip connecting the ports of two functional blocks cross each other all over the place. At this late stage of the process, it is too
expensive to redo the routing. Instead, the engineers have to bridge the signals, using the third dimension, so that no two signals cross. However, bridging is a complicated operation, and thus it is desirable to bridge as few signals as possible. The call for a computer program that finds the maximum number of signals which may be connected on the silicon surface without rossing each other, is imminent. Bearing in mind that there may be housands of signal ports at the boundary of a functional block, the problem asks quite a lot of the programmer. Are you up to the task?

Figure 1. To the left: The two blocks' ports and their signal mapping (4,2,6,3,1,5). To the right: At most three signals may be routed on the silicon surface without crossing each other. The dashed signals must be bridged.

A typical situation is schematically depicted in figure 1. The ports of the two functional blocks are numbered from 1 to p, from top to bottom. The signal mapping is described by a permutation of the numbers 1 to p in the form of a list of p unique numbers in the range 1 to p, in which the i:th number pecifies which port on the right side should be connected to the i:th port on the left side.
Two signals cross if and only if the straight lines connecting the two ports of each pair do.
 

Input
On the first line of the input, there is a single positive integer n, telling the number of test scenarios to follow. Each test scenario begins with a line containing a single positive integer p<40000, the number of ports on the two functional blocks. Then follow p lines, describing the signal mapping: On the i:th line is the port number of the block on the right side which should be connected to the i:th port of the block on the left side.
 

Output
For each test scenario, output one line containing the maximum number of signals which may be routed on the silicon surface without crossing each other.
 

Sample Input
  
  
4 6 4 2 6 3 1 5 10 2 3 4 5 6 7 8 9 10 1
8
8 7 6 5 4 3 2 1 9 5 8 9 2 3 1 7 4 6
 

Sample Output
  
  
3 9 1 4

题意:

给出当前连线的顺序,求最多可以有多少连线不交叉,输出最多有几个!


分析:

分析一下题意就可以发现,这道题相当于求最长单调子序列的问题...............

因为此题处理的数据是有序的,那么查找的时候用二分查找就相当便利了.....


讲解求最长单调子序列:


如何求最大单调子序列呢,一个比较经典的方法就是:

每次假设下一个数据是 x,根据 x 的大小,两种处理方法..... 

如果x 小于末端数据,那么找到查找序列中第一个(数组下标最小)大于 x 的数,把这个数更新成 x ,-----(1)

如果 x 大于末端数据,那么序列就延伸一个长度(长度 +1 ),末端数据现在是 x ,------(2)

依次进行,最后求得的长度便是需要的数据........


今天是第一次做这种求最长递增序列的题,感觉这样的方法真是太好了,自己也是够笨的,当初没有总结出来,晕死!!

当初自己也这样想了,但是没继续想下去,唯一的卡点就是当时一直不太明白怎么处理后面的有序元素,没想到这个方法这么巧妙,

第一种情况的处理方式,(1),这样依次进行下去,当前的序列的最大长度虽然保持不变,但是后续元素的递增序列也已经保存在了当前序列中,

第二种情况的处理方法,(2),这是上一步那样一直保存后续元素的递增序列到达了极限,那么就把最后一个元素更新掉,相当于去掉了这个序列的瓶颈,也就是这个序列的最大值,更有利于后续元素的处理,

按这两种操作下去,不但不会使得序列的中的元素顺序混乱,还不会把后续元素可能存在的最长序列丢弃掉了,

比如当前为6 7 8 ,后面有一个 1 2 3 4,

第一步更新;变成 1 7 8,然后是 1 2 8 ,再然后 1 2 3,这些步骤都是(1),继续往后,发现个4,那么4大于末尾元素 3 ,就延伸序列为 1 2 3 4 !

依次操作,当然不会发生意外啦~~~


其实求得的序列不是最长单调子序列,因为有些元素可能被更新掉了,但是长度是最长单调子序列的长度,

也就是说,这样的方法下来,这个序列的长度只会增加,不会减少,只有见到比它长的才增加,否则就一直相应的累计,也许什么时候会累计到极限,也就是(2)的情况,也许不会,那么就又从(1)开始了.....


以上是自己的理解,如有偏差吗,望大神纠错!


第一次调用的二分查找函数,相对简单点.....但是需要记住函数的模板和调用参数什么的东东.....


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int x[40005],y[40005],len;
int main()
{
	int t,n,i,kase;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		len=0;
		for(i=0;i<n;++i)
		{
			scanf("%d",&x[i]);
			y[i]=0;
		}
		y[len]=x[0];//一个开端
		for(i=1;i<n;++i)
		{
			if(x[i]>y[len])//判断是否延伸序列..
			{
				y[++len]=x[i];
				continue;
			}
			kase=upper_bound(y,y+len,x[i])-y;//因为返回的是地址,想找到相应的下标,就要减去首地址
			y[kase]=x[i];
		}
		printf("%d\n",len+1);//注意是从 0 开始的
	}
	return 0;
}

然后自己感觉不够爽,完全使用函数,倒是很方便,但是不利于自己理解二分的工作原理,所以自己手动写了一个二分查找的函数....

感觉相当便捷,而且二分查找没有固定的模板,完全可以根据需要做相应的调整,关键是自己需要深刻理解这个查找的原理和下标控制.........

其实我也理解的不够,以后并慢慢学....


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int x[40005],y[40005],len;
int search(int l,int r,int s)
{
	int mid;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(y[mid]<s)
		{
			l=mid+1;
		}
		else
		{
			r=mid-1;
		}
	}
	return l;//返回的是第一个大于所给的元素的数组的下标
}
int main()
{
	int t,n,i,kase;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		len=0;
		for(i=0;i<n;++i)
		{
			scanf("%d",&x[i]);
			y[i]=0;
		}
		y[len]=x[0];
		for(i=1;i<n;++i)
		{
			if(x[i]>y[len])//判断是否延伸
			{
				y[++len]=x[i];//延伸...
				continue;
			}
			kase=search(0,len,x[i]);//找到下标
			y[kase]=x[i];//更新
		}
		printf("%d\n",len+1);
	}
	return 0;
}



重新做,第一次数组开小了,第二次用时太长了

每次做题都要先衡量一下时间的开销,相同情况下尽量选最优的解法


/*
2016年3月31日20:10 
http://blog.csdn.net/liuke19950717
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=0x3f3f3f3f;
int x[40005];
int dp[40005];
int slove(int n)
{
	memset(dp,maxn,sizeof(dp));
	dp[0]=x[0];
	for(int i=1;i<n;++i)
	{
		int tp=upper_bound(dp,dp+n,x[i])-dp;
		dp[tp]=x[i];
	}
	return lower_bound(dp,dp+n,maxn)-dp;
}
int main()
{
	int t;
	//freopen("shuju.txt","r",stdin);
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;++i)
		{
			scanf("%d",&x[i]);
		}
		printf("%d\n",slove(n));
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值