最长递增子序列 编辑距离问题 青蛙过桥 寻宝路线 回文串问题 租用游艇问题 数字三角形 至多删三个字符

最长递增子序列 编辑距离问题 青蛙过桥 寻宝路线 回文串问题 租用游艇问题 数字三角形 至多删三个字符

/*弗洛伊德算法(三重循环,中间变量, 起始点, 重点循环顺序) */

1.最长递增子序列:o(N^2)

a[],     len1 = strlen(a) 
b[] = {1}   记录I点的最长递增序列; 
for(i = 1; i < len1; i++)
{
	for(j = 0; j < i; j++)
	{
		if(a[i] > a[j] && b[i] < b[j]+1)//b[i] 等于(所有小于的数的最长子序列的长度)+ 1 
		{
			b[i] = b[j] + 1;
		 } 
	}
 } 

2 编辑距离问题 (30 分)
设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。
这里所说的字符操作包括 (1)删除一个字符; (2)插入一个字符; (3)将一个字符改为另一个字符。
将字符串A变换为字符串B所用的最少字符操作数称为字符串A到 B的编辑距离,记为d(A,B)。 对于给定的字符串A和字符串B,计算其编辑距离 d(A,B)。

dd[i][j]//a串0-i变到b串的0-j的最短编辑问题;
 
for(i = 0; i <= len1; i++)//某一个串到了0,能一个串剩下的都要删掉,所以编辑距离为i; 
	{
		dd[0][i] = i;
		dd[i][0] = i; 
	}
	for(i = 1; i <= len1; i++)
	{
		for(j = 1; j <= len2; j++)
		{
			if(a[i] == b[j])    t = 0;
			else	t = 1;
			dd[i][j] = min(dd[i-1][j]+1, dd[i][j-1]+1, dd[i-1][j-1] + t);// min 找出三个数最小的值,三个值分别是插入一个, 删一个,
																		//改变一个; 
		}
	}
	cout<<dd[len1][len2];	

3 青蛙过桥 (25 分)
一座长度为n的桥,起点的一端坐标为0,且在整数坐标i处有a[i]个石头【0<=a[i]<=4】,
一只青蛙从坐标0处开始起跳,一步可以跳的距离为1或2或3【即每一步都会落在整数点处】,
青蛙落在i处会踩着该点的所有石头,求青蛙跳出这座桥最少踩多少个石头?并且输出依次跳
过的坐标点路线,如果存在多种路线,输出字典序最小的那一条。

输入格式:
第一行整数n(<150000),接着下一行会有n+1个由空格隔开的整数,即桥上各个坐标处石头数量。

输出格式:
第一行为踩着最少石头个数,第二行为依次跳过的坐标点【字典序最小的】。

输入样例:
在这里给出两组输入。例如:

10
1 2 1 3 0 3 1 2 1 1 2
100
1 2 0 4 0 1 3 4 2 2 1 3 1 4 0 3 0 1 2 3 3 2 2 0 1 0 0 0 0 1 2 1 3 4 0 3 4 4 1 0
4 1 3 1 1 2 3 4 4 4 0 2 0 1 1 1 3 1 3 2 1 2 4 1 2 1 4 1 0 0 1 2 3 0 2 4 4 0 0 4
2 0 0 2 1 3 3 3 0 0 2 0 0 1 2 4 2 2 2 4 0

void ff(int n)// 这个函数作用就是自底向上递推求踩点数最少; 
{
	int t, j, i;
	for(i = n; i >= 1; i--)
	{
		t = Max(c[1], c[2], c[3]);
		j = c[t];
		
		c[3] = c[2];
		c[2] = c[1];
		c[1] = j + a[i];
		b[i] = c[1];
	}
}



void fff(int n, int k)// n 代表桥的总数, K代表当前在那个点上;
						//此函数的作用是负责输入路线, 
{
	int t;
	if(n - 3 >= k)
	{
		if(k == 1)
			cout<<k-1;
		else	cout<<" "<<k-1;
		t = Max(b[k+1], b[k+2], b[k+3]);//max 函数就是求三个数最大值, 
		fff(n, k+t);
	}
	else
	{
		cout<<" "<<k-1;
	}
		
	
}

4 寻宝路线 (40 分)
在一个m行n列方格矩阵中,每一个方格内摆放着价值不等的宝贝(价值可正可负)
,让小明感到好奇的是,从左上角到达右下角的所有可能路线中,能捡到宝贝的价值总和最大是多少?
而且这种达到最大值的路线 又有多少条?【注意:只能从一个格子向下或向右走到相邻格子,并且走到的格子宝贝一定会被捡起。】

输入格式:
第一行为整数m,n(均不大于100),下一行开始会有一个m行n列的整数方阵,对应方格矩阵中的宝贝价值(这些值的绝对值都不超过500)。

输出格式:
单独一行输出2个整数,分别为能捡到宝贝价值总和的最大值和达到最大值的路线数量,2个整数间隔一个空格。

输入样例:
在这里给出一组输入。例如:

4 5
2 -1 6 -2 9
-3 2 5 -5 1
5 8 3 -2 4
5 2 8 -4 7

可能看着比较复杂,只是条件控制语句没有优化;

void fff(int x, int y, int n, int m)// m, n 很显然是问题的规模,x, y是当前的在的左边,都是从坐标1,1 开始的 
{
	if(x > 0 && x <= n && y > 0 && y <= m)
	{
		if(x == n && y == m)
		{	}
		else
		{
			if(x + 1 > n)
			{
				if(y +1 > n)
				{
				}
				else fff(x, y+1, n, m);
			}
			else
			{
				if(y+1 > n)
					fff(x+1, y, n, m);
				else
				{
					if(b[x][y+1] == b[x+1][y])
					{
						z++;
						fff(x, y+1, n, m);
						fff(x+1, y, n, m);
					}
					else
					{
						if(b[x+1][y] > b[x][y+1])
							fff(x+1, y, n, m);
						else	fff(x, y+1, n, m);
					}
				}
			}
					
		}
	}
	
}

5 回文串问题 (25 分)
一个字符串,如果从左到右读和从右到左读是完全一样的,比如"aba",我们称其为回文串。
现在给你一个字符串,可在任意位置添加字符,求最少添加几个字符,才能使其变成一个回文串。

输入格式:
任意给定的一个字符串,其长度不超过1000.

输出格式:
能变成回文串所需添加的最少字符数。

输入样例:
在这里给出一组输入。例如:

Ab3bd
Abb

# include<iostream>
# include<cstring> 
using namespace std;

int d[1001][1001];//都初始化为-1; 

int ff(string a, int x, int y)//x, y分别代表起点和终点,此程序是从首尾两端同时向中间推的; 
{
	int i, j;
	if(x <= y)
	{
		if(a[x] == a[y])//首尾相等进行下一个, 
		{
			if(d[x+1][y-1] != -1)
			{
				d[x][y] = d[x+1][y-1];
				return d[x][y];
			}		
			else
			{
				d[x][y] = ff(a, x+1, y-1);
				return d[x][y];
			}
		}
		else//不相等,左添加一个,或右边添加一个; 
		{
			if(d[x+1][y] != -1)
				i = d[x+1][y] + 1;
			else    i = ff(a, x+1, y) + 1;
			
			
			if(d[x][y-1] != -1)    j = d[x][y-1] + 1;
			else	j = ff(a, x, y-1) + 1;
			 
			 d[x][y] = i > j ? j : i;
			 return d[x][y];
		}
	}
	else	
		return 0;
}
int main()
{
	
	int i, j;
	string a;
	cin>>a;
	for(i = 0; i <= 1000; i++)
		memset(d[i], -1, 4*1000);
	int len = a.size();
	
	
	cout<<ff(a, 0, len-1);
	return 0;
}

6 租用游艇问题 (15 分)
题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,
并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i<j<=n。
试设计一个算法,计算出从游艇出租站1 到游艇出租站n所需的最少租金。

输入格式:
第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, … , 第n站的租金。

输出格式:
输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:
在这里给出一组输入。例如:

3
5 15
7
输出样例:
在这里给出相应的输出。例如:

12

//实际上是用的回溯算法;
# include

using namespace std;

int a[200][200];
int max1 = 100000000;
int num = 0;


void ff(int n, int k)
{
	int i;
	if(k <= n)
	{
		for(i = k+1; i <= n; i++)
		{
			num += a[k][i];
			ff(n, i);
			num -= a[k][i]; 
		}
	}
	if(k == n)
	{
		if(num < max1)  max1 = num;
	}
}

int main()
{
	int i, j, n;
	scanf("%d", &n);
	for(i = 1; i < n; i++)
	{
		for(j = i+1; j <= n; j++)
			scanf("%d", &a[i][j]);
	}
	ff(n, 1);
	printf("%d", max1);
	
	return 0;
}

7 数字三角形 (30 分)
给定一个由 n行数字组成的数字三角形如下图所示。试设计一个算法,
计算出从三角形 的顶至底的一条路径(每一步可沿左斜线向下或右斜线向下),使该路径经过的数字总和最大。

输入格式:
输入有n+1行:

第 1 行是数字三角形的行数 n,1<=n<=100。

接下来 n行是数字三角形各行中的数字。所有数字在0…99 之间。

输出格式:
输出最大路径的值。

输入样例:
在这里给出一组输入。例如:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出样例:
在这里给出相应的输出。例如:

30
//循环性写法,C

# include<stdio.h>

int a[105][105];
int b[105][105];
int max(int a, int b)
{
	return a > b ? a : b;	
} 

int main()
{
	int i, j;
	int n;
	scanf("%d", &n);
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= i; j++)
			scanf("%d", &a[i][j]);
	}
	
	for(i = 1; i <= n; i++)
		b[n][i] = a[n][i];
	for(i = n-1; i >= 1; i--)
	{
		for(j = 1; j <= i; j++)
		{
			b[i][j] = max(b[i+1][j], b[i+1][j+1]) + a[i][j];
		}
	}
	printf("%d", b[1][1]);
	return 0;
 } 

8 至多删三个字符 (35 分)
给定一个全部由小写英文字母组成的字符串,允许你至多删掉其中 3 个字符,结果可能有多少种不同的字符串?

输入格式:
输入在一行中给出全部由小写英文字母组成的、长度在区间 [4, 10
?6
?? ] 内的字符串。

输出格式:
在一行中输出至多删掉其中 3 个字符后不同字符串的个数。

输入样例:
ababcc
输出样例:
25
提示:

删掉 0 个字符得到 “ababcc”。

删掉 1 个字符得到 “babcc”, “aabcc”, “abbcc”, “abacc” 和 “ababc”。

删掉 2 个字符得到 “abcc”, “bbcc”, “bacc”, “babc”, “aacc”, “aabc”, “abbc”, “abac” 和 “abab”。

删掉 3 个字符得到 “abc”, “bcc”, “acc”, “bbc”, “bac”, “bab”, “aac”, “aab”, “abb” 和 “aba”。

作者: 曹鹏
单位: Google
时间限制: 400 ms
内存限制: 64 MB

#include<bits/stdc++.h>
#define N 1000002

typedef long long LL; 
char S[N];
LL F[N][4]; 

/*LL dp1(int i,int j)//由于i可达到100万,递归深度会超出 ,所以要写成循环型 
{
	if(j<0||j>i)    return 0;
	if(F[i][j])     return F[i][j];
	if(j==0||j==i)  return F[i][j]=1;
	else
	{
		int k,t=0;
		for(k=i-1;k>=i-j;k--)
		    if(S[k]==S[i])  { t=f(k-1,j+k-i); break;}
		return F[i][j] = f(i-1,j)+f(i-1,j-1)-t;
	}
}
	思路:d[i][j]表示前i个字符中删除j个字符后得到的不同字符串的个数。则

d[i][j+1]+=d[i-1][j](删除第i个字符)

d[i][j]+=d[i-1][j](不删除第i个字符)

如果只是这样转移肯定会有重复的。例如一个字符串cdabnaxy,你删除abn和删除bna后得到的字符串都是cdaxy。

这时候就要去重了,根据上面那个栗子可以发现对于一个字符s[i],如果在i之前存在一个x使得s[x]=s[i],那么删除[x,i-1]间的字符 和删除[x+1,i]间的字符其实是重复的,等价的,那么d[i][j]就要减去d[x-1][j-(i-x)],减去删除这段造成的重复串。

	*/

int main()
{
	int n=1,i,j,k;
	scanf("%s",S+1);
	n=strlen(S+1);
	for(i=0;i<=n;i++)
	  for(j=0;j<=3;j++)
	    if(j==0||j==i)  F[i][j]=1;
	    else if(j<i)
	    {	       
		   F[i][j] = F[i-1][j]+F[i-1][j-1];
		   for(k=i-1;k>=i-j;k--)//如果k<i-j隔的太远了,不会有重复的了
		      if(S[k]==S[i])
			  {
			  	 F[i][j] -= F[k-1][j+k-i];
			  	 break;
			  }
	    }
	printf("%lld\n",F[n][0]+F[n][1]+F[n][2]+F[n][3]);
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值