算法设计与分析

在这里插入图片描述

贪心算法

1.跳跳

题目描述

你是一只小跳蛙,你特别擅长在各种地方跳来跳去。

这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 i i i 块的石头高度为 h i h_i hi,地面的高度是 h 0 = 0 h_0 = 0 h0=0。你估计着,从第 i i i 块石头跳到第 j j j 块石头上耗费的体力值为 ( h i − h j ) 2 (h_i - h_j) ^ 2 (hihj)2,从地面跳到第 i i i 块石头耗费的体力值是 ( h i ) 2 (h_i) ^ 2 (hi)2

为了给小 F 展现你超级跳的本领,你决定跳到每个石头上各一次,并最终停在任意一块石头上,并且小跳蛙想耗费尽可能多的体力值。

当然,你只是一只小跳蛙,你只会跳,不知道怎么跳才能让本领更充分地展现。

不过你有救啦!小 F 给你递来了一个写着 AK 的电脑,你可以使用计算机程序帮你解决这个问题,万能的计算机会告诉你怎么跳。

那就请你——会写代码的小跳蛙——写下这个程序,为你 NOIp AK 踏出坚实的一步吧!

输入格式

输入一行一个正整数 n n n,表示石头个数。

输入第二行 n n n 个正整数,表示第 i i i 块石头的高度 h i h_i hi

输出格式

输出一行一个正整数,表示你可以耗费的体力值的最大值。

样例 1
样例输入 1
2
2 1
样例输出 1
5

样例 2

样例输入 2
3
6 3 5
样例输出 2
49

提示

样例解释

两个样例按照输入给定的顺序依次跳上去就可以得到最优方案之一。

数据范围

对于 1 ≤ i ≤ n 1 \leq i \leq n 1in,有 0 < h i ≤ 1 0 4 0 < h_i \leq 10 ^ 4 0<hi104,且保证 h i h_i hi 互不相同。

对于 10 % 10\% 10% 的数据, n ≤ 3 n \leq 3 n3

对于 20 % 20\% 20% 的数据, n ≤ 10 n \leq 10 n10

对于 50 % 50\% 50% 的数据, n ≤ 20 n \leq 20 n20

对于 80 % 80\% 80% 的数据, n ≤ 50 n \leq 50 n50

对于 100 % 100\% 100% 的数据, n ≤ 300 n \leq 300 n300

c++实现

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
	int a[333];
	int n,h=0;
	cin>>n;
	a[0]=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a,a+n+1);
	int i=0,j=n;
	while(i<j){
		h += pow(a[i] - a[j], 2);
		i++;
		h += pow(a[i] - a[j], 2);
		j--;
	}
	cout<<h;
	return 0;
} 

2.

题目描述

给出n个正整数,将他们排成一排组成一个最大的正整数。

在这里插入图片描述
设计解决这一问题的贪心策略。

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
/*最大*/
bool cmp1(string a,string b){
	return a+b > b+a;
}
/*最小*/ 
//bool cmp2(string a,string b){
//	return a+b<b+a;
//}
int main(){
	string a[100000];
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n,cmp1);
	cout<<"Max=";
	for(int i=0;i<n;i++){
		cout<<a[i];
	}
//	sort(a,a+n,cmp2);
//	cout<<"\tMin=";
//	for(int i=0;i<n;i++){
//		cout<<a[i];
//	}
	return 0;
} 

DFS(深度优先搜索【回溯算法】)

1.装载问题

给定n个集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。集装箱装载问题要求确定在不超过轮船载重量的前提下,将尽可能多的集装箱装上轮船(贪心算法中的装载问题讨论的是装载件数;本题讨论的是最大装载重量。)

由于集装箱问题是从n个集装箱里选择一部分集装箱,假设解向量为X(x1, x2, …, xn),其中xi∈{0, 1}, xi =1表示集装箱i装上轮船, xi =0表示集装箱i不装上轮船。

输入

每组测试数据:第1行有2个整数c和n。C是轮船的载重量(0<c<30000),n是集装箱的个数(n≤20)。第2行有n个整数w1, w2, …, wn,分别表示n个集装箱的重量。

输出

对每个测试例,输出两行:第1行是装载到轮船的最大载重量,第2行是集装箱的编号。

样例:

样例输入
34 3
21 10 5
样例输出
31
1 2
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int w[NUM];			/*集装箱重量集合*/
int x[NUM];			/*当前搜索的解向量*/
int r;				/*剩余集装箱的重量*/
int cw;				/*当前轮船的载重量*/
int bestw;			/*当前最优载重量*/
int bestx[NUM]; 	/*当前最优解*/
void BackTrack(int t,int c,int n){
	/*到达叶子结点*/
	if(t>n){
		if(cw>bestw){
			/*更新最优解*/
			for(int i=1;i<=n;i++){
				bestx[i]=x[i];
			}
			bestw=cw;
		}
		return;
	}
	/*更新剩余集装箱的重量*/
	r-=w[t];
	/*搜索左子树*/
	if(cw+w[t]<=c){
		x[t]=1;
		cw+=w[t];
		BackTrack(t+1,c,n);
		cw-=w[t];
	}
	/*搜索右子树*/
	if(cw+r>bestw){
		x[t]=0;
		BackTrack(t+1,c,n);
	}
	r+=w[t];
}
int main() {
	//freopen("in.txt","r",stdin);
	int n,c;
	cin>>c>>n;
	for(int i=1;i<=n;i++){
		cin>>w[i];
		r+=w[i];	/*初始化剩余集装箱的重量*/
	}
	BackTrack(1,c,n);
	cout<<bestw<<endl;
	for(int i=1;i<=n;i++){
		if(bestx[i]==1)
		cout<<i<<" ";
	}
	//fclose(stdin);
	return 0;
}

2. 0-1背包问题

给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。

输入:第一个数据是背包的容量为c(1≤c≤1500),第二个数据是物品的数量为n(1≤n≤50)。接下来n行是物品i的重量是wi,其价值为vi。所有的数据全部为整数,且保证输入数据中物品的总重量大于背包的容量。当c=0时,表示输入数据结束。
输出:对每组测试数据,输出装入背包中物品的最大价值。
样例:

输入样例输出样例
50 3220
10  60
30 120
20 100
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int cw;		/*当前重量*/
int cv;		/*当前价值*/
int bestv;	/*当前最优价值*/

struct goods{
	int w;  	/*物品重量*/
	int v;  	/*物品价值*/
	double d;	/*物品单位价值重量比*/
}Q[NUM];

bool cmp(goods a,goods b){
	return a.d>=b.d;
}

int add(int t,int c,int n){
	int cleft=c-cw;	/*背包剩余容量*/
	int b=cv;		/*上界*/
	while(t<n&&Q[t].w<=cleft){
		cleft-=Q[t].w;
		b+=Q[t].v;
		t++;
	}
	if(t<n){
		b+=1.0*Q[t].v/Q[t].w;
	}
	return b;
}

void DFS(int t,int c,int n){
	if(t>n){
		bestv=cv;
		return;
	}
	if(cw+Q[t].w<=c){
		cw+=Q[t].w;
		cv+=Q[t].v;
		DFS(t+1,c,n);
		cw-=Q[t].w;
		cv-=Q[t].v;
	}
	if(add(t+1,c,n)>bestv){
		DFS(t+1,c,n);
	}
}


int main() {
	//freopen("in.txt","r",stdin);
	int c,n;
	cin>>c>>n;
	for(int i=0;i<n;i++){
		cin>>Q[i].w>>Q[i].v;
		Q[i].d=1.0*Q[i].v/Q[i].w;
	}
	sort(Q,Q+n,cmp);
	DFS(0,c,n);
	cout<<bestv<<endl;
	//fclose(stdin);
	return 0;
}

3.图的m着色问题

给定无向连通图G=(V, E)和m种不同的颜色,用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中相邻的两个顶点有不同的颜色?

若一个图最少需要m种颜色才能使图中每条边连接的两个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。

编程计算:给定图G=(V, E)和m种不同的颜色,找出所有不同的着色法和着色总数。

输入样例输出样例
5 4
1 3
1 2
1 4
2 3
2 4
2 5
3 4
4 5
0 0
1 2 3 4 1
1 2 3 4 3
1 2 4 3 1
1 2 4 3 4
1 3 2 4 1
1 3 2 4 2
1 3 4 2 1

4 3 2 1 4
Total=48
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int a[NUM][NUM];/*图的邻接矩阵*/
int x[NUM];		/*当前的解向量*/
int sum;		/*已经找到的可m着色的方案数量*/

/*将相邻边转化为邻接矩阵*/
void T(int x,int y,int n){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			a[x][y]=1;
			a[y][x]=1;
		}
	}
}

bool Same(int t,int m,int n){
	for(int i=1;i<=n;i++){
		if((a[t][i]==1)&&(x[i]==x[t])){
			return false;
		}
	}
	return true;
}

void DFS(int t,int m,int n){
	if(t>n){
		sum++;
		for(int i=1;i<=n;i++){
			cout<<x[i]<<" ";
		}
		cout<<endl;
	}else{
		for(int i=1;i<=m;i++){
			x[t]=i;
			if(Same(t,m,n)){
				DFS(t+1,m,n);
			}
			x[t]=0;
		}
	}
} 
int main() {
	//freopen("in.txt","r",stdin);
	int m,n,a,b;
	cin>>n>>m;
	while(cin>>a>>b){
		T(a,b,n);
	}
	DFS(1,m,n);
	cout<<"Total="<<sum<<endl;
	//fclose(stdin);
	return 0;
}

4.n皇后问题

在n×n格的棋盘上放置彼此不受攻击的n个皇后。
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n皇后问题等价于在n×n格的棋盘上放置n个皇后,任何两个皇后不放在同一行或同一列或同一斜线上。
编程要求:找出一个n×n格的棋盘上放置n个皇后并使其不能互相攻击的所有方案。

输入样例输出样例
51 3 5 2 4
1 4 2 5 3
2 4 1 3 5
2 5 3 1 4
3 1 4 2 5
3 5 2 4 1
4 1 3 5 2
4 2 5 3 1
5 2 4 1 3
5 3 1 4 2

Total= 10
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int x[NUM];	/*解向量*/
int sum;	/*当前已经找到的可行方案数*/

bool Place(int t){
	for(int i=1;i<t;i++){
		if((x[i]==x[t])||(abs(t-i)==abs(x[i]-x[t]))){
			return false;
		}
	}
	return true;
} 

void DFS(int t,int n){
	if(t>n){
		sum++;
		for(int i=1;i<=n;i++){
			cout<<x[i]<<" ";
		}
		cout<<endl;
	}else{
		for(int i=1;i<=n;i++){
			x[t]=i;
			if(Place(t)){
				DFS(t+1,n);
			}
//			x[t]=0;
		}
	}
}
int main() {
	//freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	DFS(1,n);
	cout<<"Total="<<sum<<endl;
	//fclose(stdin);
	return 0;
}

BFS(广度优先搜索【分支限界算法】)

1.细胞矩阵

一矩形阵列由数字0到9组成,数字1到9代表细胞数字,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如阵列 :
4 10
0234500067
1034560500
2045600671
0000000089
有4个细胞。

输入
矩阵的行列值 m和n
以及这个矩阵
输出
细胞的个数
样例输入
4 10
0234500067
1034560500
2045600671
0000000089
样例输出
4

【算法分析】
⑴读入m*n矩阵阵列,将其转换为boolean矩阵存入bz数组中;
⑵沿bz数组矩阵从上到下,从左到右,找到遇到的第一个细胞;
⑶将细胞的位置入队h,并沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为false;
⑷将h队的队头出队,沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为false;
⑸重复4,直至h队空为止,则此时找出了一个细胞;
⑹重复2,直至矩阵找不到细胞;
⑺输出找到的细胞数。

#include<bits/stdc++.h>
#define N 1000
using namespace std;
struct site {
	int x;
	int y;
};
int dx[4]= {-1,0,1,0};	/*上下走*/
int dy[4]= {0,1,0,-1};	/*左右走*/
int bz[N][N];			/*细胞矩阵*/
int ans=0;				/*细胞数*/
int m,n;				/*矩阵行数、列数*/
void bfs(int p,int q) {
	queue<site> qc;
	ans++;
	site s,f;
	s.x=p;
	s.y=q;
	qc.push(s);
	while(!qc.empty()) {
		f=qc.front();
		qc.pop();
		for(int i=0; i<4; i++) {
			s.x=f.x+dx[i];
			s.y=f.y+dy[i];
			if((s.x>=0)&&(s.x<m)&&(s.y>=0)&&(s.y<n)&&(bz[s.x][s.y])) {
				qc.push(s);
				bz[s.x][s.y]=0;
			}
		}
	}
}

int main() {
	//freopen("in.txt","r",stdin);
	char s[N];
	cin>>m>>n;
	cin.get();
	for (int i=0; i<m; i++ )
		for (int j=0; j<n; j++ )
			bz[i][j]=1;
	for (int i=0; i<m; i++) {
		gets(s);
		for (int j=0; j<n; j++)
			if (s[j]=='0')
				bz[i][j]=0;
	}
	for (int i=0; i<m; i++)
		for (int j=0; j<n; j++)
			if (bz[i][j]) {
				bz[i][j]=0;
				bfs(i,j);
			}
	cout<<ans<<endl;
	//fclose(stdin);
	return 0;
}

2.最小步数

在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。

输入样例
12 16
18 10
输出样例
8  9

#include<bits/stdc++.h>
using namespace std;
struct s{
	int x;	//横坐标 
	int y;	//纵坐标 
	int ans;//(1,1)-->(x,y)的步数 
};
int x[12]={1,2,2,1,2,2,-1,-2,-2,-1,-2,-2};
int y[12]={2,1,2,-2,-1,-2,2,1,2,-2,-1,-2};
int main(){
	int a[101][101];
	int m1,n1,m2,n2;
	queue<s> q;
	s ss,ff;
	memset(a,0xff,sizeof(a));
	ss.x=ss.y=1;ss.ans=0;
	q.push(ss);
	cin>>m1>>n1>>m2>>n2;
	while(!q.empty()){
		ff=q.front();
		for(int i=0;i<12;i++){
			int dx=ff.x+x[i];
			int dy=ff.y+y[i];
			if(dx>0&&dy>0&&dx<=100,dy<=100){
			
				if(a[dx][dy]==-1){
					a[dx][dy]=ff.ans+1;
					ss.x=dx;ss.y=dy;ss.ans=a[dx][dy];
					q.push(ss);
					if(a[m1][n1]>0&&a[m2][n2]>0){
						cout<<a[m1][n1]<<endl;
						cout<<a[m2][n2]<<endl;
						return 0;
					}
				}
			}
		}
		q.pop();
	}
}

3.装载问题

给定n个集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为wi。集装箱装载问题要求确定在不超过轮船载重量的前提下,将尽可能多(重量)的集装箱装上轮船。
由于集装箱问题是从n个集装箱里选择一部分集装箱,假设解向量为X(x1, x2, …, xn),其中xi∈{0, 1}, xi =1表示集装箱i装上轮船, xi =0表示集装箱i不装上轮船。

输入:每组测试数据:第1行有2个整数c和n。C是轮船的载重量(0<c<30000),n是集装箱的个数(n≤20)。第2行有n个整数w1, w2, …, wn,分别表示n个集装箱的重量。

输出:对每个测试例,输出装载到轮船的最大载重量

输入样例
80 4
18 7 25 36
输出样例
79

#include<bits/stdc++.h>
#define N 1000
using namespace std;
int cw;		/*当前重量*/
int bestw;	/*不超过载重量的最大重量*/
int r;		/*剩余重量*/
int w[N];	/*集装箱重量*/
int c;		/*轮船载重量*/
int n;		/*集装箱个数*/

int bfs(){
	queue<int> q;
	q.push(-1);
	int i=0;
	for(int j=0;j<n;j++){
		r+=w[j];
	}
	while(1){
		int wt=cw+w[i];
		if(wt<=c){
			if(wt>bestw){
				bestw=wt;
			}
			if(i<n){
				q.push(wt);
			}
		}
		if(cw+r>bestw&&i<n){
			q.push(cw);
		}
		cw=q.front();
		q.pop();
		if(cw==-1){
			if(q.empty()){
				return bestw;
			}
			q.push(-1);
			cw=q.front();
			q.pop();
			i++;
			r-=w[i];
		}
	}
	return bestw;
}	

int main(){
	//freopen("in.txt","r",stdin);
	cin>>c>>n;
	for(int i=0;i<n;i++){
		cin>>w[i];
	}
	cout<<bfs()<<endl;
	//fclose(stdin);
	return 0;
}

DP(动态规划)

1.数字三角形

数字三角形,从顶部出发,在每一结点可以选择向左走或者向右走,一直走到底层。
试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。

动态规划方程: a[i][j]=max(a[i+1][j],a[i+1][j+1])


输入样例
6
9
12 15
10  6  8
 2  18 9  5
19  7 10 4  16
输出样例
59

#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int x[NUM][NUM];/*存数字三角形*/	
/*向左走i++;向右走i++,j++*/
int add(int n){
	for(int i=n-2;i>=0;i--){
		for(int j=0;j<=i;j++){
			x[i][j]+=max(x[i+1][j],x[i+1][j+1]);
		}
	}
	return x[0][0];
}
int main() {
	//freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		for(int j=0;j<i;j++){
			cin>>x[i][j];
		}
	}
	cout<<add(n);
	//fclose(stdin);
	return 0;
}

2.最大子段和

问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-20,11,-4,13,-5,-2)时,最大子段和为20。
输入
输入n及n个数
输出
子段和的最大值

输入样例
6
-20 11 -4 13 -5 -2
输出样例
20

bi是i到n区间的最大子段和(i ~ n,i-1~ n,1~n,共i个子段)

/*计算最大值*/
#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int x[NUM];	/*序列*/
int sum;	/*最大子段和*/
int y;		/*i到n的最大子段和*/	
int add(int n){
	for(int i=n;i>0;i--){
		if(y>0){
			y+=x[i];
		}else{
			y=x[i];
		}
		if(y>sum){
			sum=y;
		}
	}
	return sum;
}
int main() {
	//freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>x[i];
	}
	cout<<add(n);
	//fclose(stdin);
	return 0;
}
/***********************************/
/*计算子段和的最优解*/
/*
输入:
8
1 -3 7 8 -4 12 -10 6
输出:
23
3->6
*/

#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int x[NUM];		/*序列*/
int add(int n,int &p,int &q) {
	int sum;	/*最大子段和*/
	int y;		/*i到n的最大子段和*/
	int begin=0;
	for(int i=n; i>=1; i--) {
		if(y>0) {
			y+=x[i];
		} else {
			y=x[i];
			begin=i+1;
		}
		if(y>sum) {
			sum=y;
			p=i+1;
			q=begin;
		}
	}
	return sum;
}
int main() {
	//freopen("in.txt","r",stdin);
	int n,p,q;
	cin>>n;
	for(int i=0; i<n; i++) {
		cin>>x[i];
	}
	cout<<add(n,p,q)<<endl;
	cout<<p<<"->"<<q<<endl;
	//fclose(stdin);
	return 0;
}

3.最长单调递增子序列

输入
8
65 158 170 155 239 300 207 389
输出
6

#include<bits/stdc++.h>
#define NUM 1000
using namespace std;

int x[NUM];	/*序列*/
int y[NUM];	/*记录以a[i]为结尾的元素的最长递增子序列的长度*/

int add(int n) {
	int m=0;/*最终结果*/
	y[1]=1;
	for(int i=2;i<=n;i++) {
		int k=0;
		for(int j=1;j<i;j++){
			if(x[j]<=x[i]&&k<y[j]){
				k=y[j];
			}
		}
		y[i]=k+1;
		if(m<y[i]){
			m=y[i];
		}
	}
	return m;
}
int main() {
	//freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x[i];
	}
	cout<<add(n);
	//fclose(stdin);
	return 0;
}

4. 0-1背包问题

给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。

输入样例
5  4
2 12
1 10
3 20
2 15
输出样例
37

分析:
阶段:
i~n ,依次处理每一件物品
状态
背包的容量:0~m
决策
在第i阶段,在背包容量是v(0~m之间) 的情况下,如何处理第i 件物品,才能使装入背包中的物品最大。
f[i][v]表示前i件物品(部分或全部)放入一个容量为v的背包可以获得的最大价值。处理方案:
在w[i]>v的情况下,不装入;
f[i][v]=f[i-1][v]
否则,根据
max{f[i-1][v],f[i-1][v-w[i]]+c[i]}
进行决策
状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-w[i]]+c[i]}。

#include<bits/stdc++.h>
#define N 1000
using namespace std;
int w[N],v[N],f[N][N];
int main() {
	int c,n;
	//freopen("in.txt","r",stdin);
	cin>>c>>n;
	for(int i=1; i<=n; i++) {
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=c;j>0;j--){
			if(w[i]<=j){
				f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
			}else{
				f[i][j]=f[i-1][j];
			}
		}
	}
	cout<<f[n][c]<<endl;
	//fclose(stdin);
	return 0;
/*优化空间复杂度*/
#include<bits/stdc++.h>
#define N 1000
using namespace std;
int w[N],v[N],f[N];
int main() {
	int c,n;
	//freopen("in.txt","r",stdin);
	cin>>c>>n;
	for(int i=1; i<=n; i++) {
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=c;j>=w[i];j--){
			if(f[j-w[i]]+v[i]>f[j]){
				f[j]=f[j-w[i]]+v[i];
			}
		}
	}
	cout<<f[c]<<endl;
	//fclose(stdin);
	return 0;
}

5.最长公共子序列

描述
若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。

输入
三行.第一行m和n,分别表示两个子序列的长度(符号的个数)
接下来两行,分别表示X和Y
输出
最长公共子序列的长度

样例输入
7 6
ABCBDAB
BDCABA
样例输出
4

#include<bits/stdc++.h>
#define N 1000
using namespace std;
int l[N][N];
int max(int a,int b){
	if(a>=b) return a;
	else 	 return b;
}
int LCS(int m,int n,char x[],char y[]){
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(x[i]==y[j]){
				l[i][j]=l[i-1][j-1]+1;
			}else{
				l[i][j]=max(l[i-1][j],l[i][j-1]);
			}
		}
	}
	return l[m][n];
}
int main() {
	//freopen("in.txt","r",stdin);
	char x[N],y[N];
	int m,n;
	cin>>m>>n;
	for(int i=1;i<=m;i++) cin>>x[i];
	for(int j=1;j<=n;j++) cin>>y[j];
	cout<<LCS(m,n,x,y)<<endl;
	//fclose(stdin);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值