DP LCS&LIS 模版 POJ1458&POJ2533&POJ1631 DP初步

一、最长公共子序列LCS

POJ1458

Common Subsequence

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 61117   Accepted: 25544

Description

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.

Input

The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.

Output

For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

Sample Input

abcfbc                abfcab
programming     contest 
abcd                   mnp

Sample Output

4
2
0

 

两个字符串求最长公共子序列:

状态转移:

当s[i]=s[j]时,当前匹配的公共子序列最大长度就是之前的最大长度+1,dp[i][j]=dp[i-1][j-1]+1;

反之,dp[i][j]=max(dp[i][j-1],dp[i-1][j]);

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
	ios::sync_with_stdio(false);

	string s1,s2;
	while(cin>>s1>>s2){
		int len1=s1.size();
		int len2=s2.size();
		int dp[len1+10][len2+10];
		memset(dp,0,sizeof(dp));	//二维数组要这样子初始化不能直接={0}!
		for(int i=1;i<=len1;++i){
			for(int j=1;j<=len2;++j){
				if(s1[i-1]==s2[j-1])	//第一项的匹配还是不能单独处理啊嘤
					dp[i][j]=dp[i-1][j-1]+1;
				else
					dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
		cout<

 

二、最长升序子序列LIS

POJ2533

Longest Ordered Subsequence

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 62466   Accepted: 27942

Description

A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1a2, ..., aN) be any sequence (ai1ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.

Input

The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000

Output

Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample Input

7
1 7 3 5 9 4 8

Sample Output

4

 

第一种时间复杂度O(n^2)的常规做法,去年寒假写的,现在看不懂了,感觉写得很迷:

#include 

int n,a[1000],num=0,dp[1001],flag;

int main()
{
    int i,j;

    scanf("%d",&n);

    for(i=0;i=dp[flag]&&a[j]num)
            num=dp[i];

    printf("%d",num);

    return 0;
}

暑假又写了一次,用了所谓的贪心+二分的优化:

贪心思想:要每个长度的升序子序列最后一位越小最后能够越长这样子,那么

如果当前位a[i]大于当前最长升序子列的末位,那么LIS的len+1,且末位为a[i];

反之,二分找到第一个大于等于a[i]的位置,即某一长度的升序子序列的末位大于等于a[i],那么那一位的末位更新为a[i];

如下:

#include 
#include 
#include 
using namespace std;

const int maxn=1000;

int main()
{
	int n;
	int a[maxn+10],low[maxn+10];
	//贪心&二分的优化
	//low的数组下标是升序子序列长度,low[i]代表升序子序列为长度i时,最后一位及最大的数最小是多少
	int len;

	while(~scanf("%d",&n)){
		memset(low,0,sizeof(low));
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
		}
		low[0]=0;
		len=1;low[1]=a[1];
		for(int i=2;i<=n;++i){
			if(a[i]>low[len]){
				low[++len]=a[i];
			}
			else{
				int pos=lower_bound(low,low+1+len,a[i])-low;	//注!当前序列长度找嘤(那个stl貌似本质是二分啊二分来全是0
				low[pos]=a[i];
			}
		}
		printf("%d\n",len);
	}

	return 0;
}

 

离散化树状数组优化LIS

先对原数组a复制一个新数组b,进行排序和去重。

再遍历原数组,对于原数组中目前遍历到的数a[i],其LIS可通过查询树状数组得到,查询参数为a[i]在排序去重数组b中的位置+1,注意树状数组从1开始,查询比该数小的各LIS中最长的那一个,+1为当前数的LIS。更新树状数组。

#include 
#include 
#include 

using namespace std;

#define lowbit(x) x&(-x)
#define N 100005

int n,m;
int a[N],b[N],c[N];
int ans=1;

int query(int x)
{
    int res=0;
    for(;x;x-=lowbit(x)){
        res=max(res,c[x]);
    }
    return res;
}

void update(int x,int val)
{
    for(;x

 

POJ1631

Bridging signals

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 16132   Accepted: 8688

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 crossing each other, is imminent. Bearing in mind that there may be thousands 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? 

DP LCS&LIS 模版 POJ1458&POJ2533&POJ1631 DP初步_第1张图片


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 specifies 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

 

题意分析:求最少去掉一些连接桥,使最后剩下的连接桥没有交叉点,且数目最大,输出最大数目。

惊了!!!居然是!!!LIS!!!

一开始还想怎么算交叉个数的我真是菜哭!

其实就是右边最长升序就不会交叉啊啊啊啊啊啊啊啊啊!

代码就和上面没什么差了,直接复制改了改输入这样子:

#include 
#include 
#include 
using namespace std;

const int maxn=40000;

int main()
{
	int t;
	int n;
	int a[maxn+10],low[maxn+10];
	//贪心&二分的优化
	//low的数组下标是升序子序列长度,low[i]代表升序子序列为长度i时,最后一位及最大的数最小是多少
	int len;

	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		memset(low,0,sizeof(low));
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
		}
		low[0]=0;
		len=1;low[1]=a[1];
		for(int i=2;i<=n;++i){
			if(a[i]>low[len]){
				low[++len]=a[i];
			}
			else{
				int pos=lower_bound(low,low+1+len,a[i])-low;	//注!当前序列长度找嘤(那个stl貌似本质是二分啊二分来全是0
				low[pos]=a[i];
			}
        }
		printf("%d\n",len);
	}

	return 0;
}

 

你可能感兴趣的:(ACM,动态规划)