某农业学校 算法设计与分析-实验2-动态规划

最长公共子序列

【问题描述】给定两个字符串text1和text2,返回这两个字符串的最长公共子序列的长度。如果不存在公共子序列,则返回0。一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

【输入形式】输入的第1行中有一个字符串,表示text1;输入的第2行中有一个字符串,表示text2。
【输出形式】输出1行一个整数,表示text1和text2的最长公共子序列的长度。
【样例输入】

abcde

ace
【样例输出】

3
【样例说明】

最长公共子序列是ace,长度为3
【说明】

1<=text1.length, text2.length<=1000

text1和text2仅有小写英文字符组成。

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
string text1,text2;
int dp[N][N];

int main()
{
	cin>>text1>>text2;
//	cout << text1.length()<<endl;
	for(int i=0;i<=text1.length();i++)
	{
		dp[i][0]=0;
	}
	for(int i=0;i<=text2.length();i++)
	{
		dp[0][i]=0;
	}
	for(int i=1;i<=text1.length();i++)
	{
		for(int j=1;j<=text2.length();j++)
		{
			if(text1[i-1]==text2[j-1])
			{
				dp[i][j]=dp[i-1][j-1]+1;
			}
			else
			{
				dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
			}
			//cout << dp[i][j]<<endl;
		}
	}
	cout<<dp[text1.length()][text2.length()];
	return 0;
}

矩阵链相乘

【问题描述】给定n个矩阵M1,M2...Mn,他们的维数分别是r1*c1,r2*c2...rn*cn,要求使用【动态规划】的策略求解矩阵连乘的最优计算代价(总乘法次数最少)。题目保证矩阵相乘一定是有效的。

例如有三个矩阵M1,M2,M3,他们的维度分别是2*10,10*2,2*10。按照矩阵乘法的结合律,可以先把M1和M2相乘,然后把结果和M3相乘,总的乘法次数为2*10*2+2*2*10=80次;也可以先把M2和M3相乘,再用M1去相乘,这种方式下总的乘法次数为10*2*10+2*10*10=400次。因此最优计算代价为80。
【输入形式】输入的第1行中有1个数字n,表示矩阵的个数;接下来n行,每行2个整数ri和ci,分别表示矩阵Mi的行数和列数。
【输出形式】输出1行中有一个数字,表示n个矩阵相乘的最优计算代价。
【样例输入】

3

2 10

10 2

2 10
【样例输出】

80
【说明】

n>=2

1<=ri,ci<=20

#include<bits/stdc++.h>
using namespace std;
const int N=30,Inf=1e8+20;
int n;
int m[N][N],a[3*N];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		m[i][i]=0;
	}
	cin>>a[0];
	int num=1;
	for(int i=1;i<2*n;i++)
	{
		int t;
		cin>>t;
		if(i%2==1)
		{
			a[num++]=t;
		}
	}
	
	for(int d=2;d<=n;d++)
	{
		for(int i=1;i<=n-d+1;i++)
		{
			int j=i+d-1;
			m[i][j]=Inf;
			for(int k=i;k<j;k++)
			{
				int temp=m[i][k]+m[k+1][j]+a[i-1]*a[k]*a[j];
				if(temp<m[i][j])
				{
					m[i][j]=temp;
				}
				//cout << m[i][j]<<" "<<i<<" "<<j<<endl;
			}
		} 
	}
	cout << m[1][n];
	return 0;
}

所有点对的最短路径问题

【问题描述】给定一个非负的加权有向图G,求其中任意两个节点之间的最短路径。
【输入形式】输入的第1行包含2个整数n和m,表示图G中包含n个节点和m条边。接下来m行,每行中有3个整数i,j,w,表示从节点i到节点j存在一条边(节点编号从1开始),该边的权重为w。
【输出形式】

输出最短路径矩阵,共包含n行,每行包含n个数字(数字之间使用空格分割),表示该节点到其他节点的最短距离。

特别地,节点到自身的距离定义为0;如果节点之间无法到达,使用1e9+7表示他们之间的距离。
【样例输入】

3 5

1 2 2

1 3 9

2 1 8

2 3 6

3 1 1
【样例输出】

0 2 8

7 0 6

1 3 0
【思考】如果出现负边,如何进行改进

#include<bits/stdc++.h>
using namespace std;
const int N=1010,inf=1e9+7;
int n,m;
int g[N][N];

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j) g[i][j]=0;
			else
			g[i][j]=inf;
		}
	}
	for(int k=1;k<=m;k++)
	{
		int i,j,w;
		cin>>i>>j>>w;
		g[i][j]=w;
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{	
				if(i==j) 
				{
					continue;	
				}
				if(g[i][k]+g[k][j]<g[i][j])
				{
					g[i][j]=g[i][k]+g[k][j];
				}
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cout << g[i][j]<<" ";
		}
		cout << endl;
	}
	
	
}

01背包问题

【问题描述】给定一个容量为C的背包,现有n个物品,每个物品的体积分别为s1,s2...sn,价值分别为v1,v2...vn。每个物品只能放入一次。背包最多能装入价值为多少的物品。
【输入形式】输入的第1行包含2个整数C和n,分别表示背包容量和物品个数。接下来n行,每行包含2个整数si和vi,分别表示物品的体积和价值。
【输出形式】输出1行中含有一个数字,表示背包能装入的物品的最大价值。
【样例输入】

9 4

2 3

3 4

4 5

5 7
【样例输出】

12

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int c,n,dp[N][N];
int s[N],v[N];

int main()
{
	cin>>c>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i]>>v[i];
		//tiji >> jiazhi
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=c;j++)
		{
			if(j<s[i])
			dp[i][j]=dp[i-1][j];
			else
			dp[i][j]=max(dp[i-1][j],dp[i-1][j-s[i]]+v[i]);
		}
	}
	cout <<dp[n][c];
	return 0; 
}


最少费用购物----动态规划

问题描述:

  商店中每种商品都有标价。例如,一朵花的价格是2 元。一个花瓶的价格是5 元。为了吸引顾客,商店提供了一组优惠商品价。优惠商品是把一种或多种商品分成一组,并降价销售。例如,3 朵花的价格不是6 元而是5 元。2 个花瓶加1 朵花的优惠价是10 元。试设计一个算法,计算出某一顾客所购商品应付的最少费用。

编程任务:

  对于给定欲购商品的价格和数量,以及优惠商品价,编程计算所购商品应付的最少费用。

数据输入:

  由文件input.txt 提供欲购商品数据。文件的第1 行中有1 个整数B(0≤B≤5),表示所购商品种类数。接下来的B 行,每行有3 个数C,K 和P。C 表示商品的编码(每种商品有唯一编码),1≤C≤999。K 表示购买该种商品总数,1≤K≤5。P 是该种商品的正常单价(每件商品的价格),1≤P≤999。请注意,一次最多可购买5*5=25 件商品。

  由文件offer.txt 提供优惠商品价数据。文件的第1 行中有1 个整数S(0≤S≤99),表示共有S 种优惠商品组合。接下来的S 行,每行的第一个数描述优惠商品组合中商品的种类数j。接着是j 个数字对(C,K),其中C 是商品编码,1≤C≤999。K 表示该种商品在此组合中的数量,1≤K≤5。每行最后一个数字P(1≤ P≤9999 )表示此商品组合的优惠价。

结果输出:

  程序运行结束时,将计算出的所购商品应付的最少费用输出到文件output.txt 中。

输入文件示例                            输出文件示例

input.txt         offer.txt              output.txt

2                    2                        14

7 3 2             1 7 3 5

8 2 5             2 7 1 8 2 10

/*
2
7 3 2
8 2 5
2
1 7 3 5
2 7 1 8 2 10
*/

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int b,s;
struct pd
{
	int c,k,p;
}p[N];
int pos[N];//用于记录商品编码的位置 
int zuhe[100][6]={0};
//zuhe[i][j]: 商品组合的优惠价(j=0);某种优惠组合中某种商品需要购买的数量(j>0)
int num[6]={0};//用于记录每个商品要买多少个
int cost[6][6][6][6][6];

void mini()
{
	int i,j,k,m,n;
	int t;
	int sum1=0;
	for(i=1;i<=b;i++)
		sum1+=num[i]*p[i].p;
	for(t=1;t<=s;t++)
	{
		i=num[1]-zuhe[t][1];
		j=num[2]-zuhe[t][2];
		k=num[3]-zuhe[t][3];
		m=num[4]-zuhe[t][4];
		n=num[5]-zuhe[t][5];
		if(i<0 || j<0 || k<0 || m<0 || n<0) continue;
		if(cost[i][j][k][m][n]+zuhe[t][0]<sum1)
		{
			sum1=cost[i][j][k][m][n]+zuhe[t][0];
		}
	}
	cost[num[1]][num[2]][num[3]][num[4]][num[5]]=sum1;
} 

void dfs(int x)
{
	if(x>b)
	{
		mini();
		return ;
	}
	for(int j=0;j<=p[x].k;j++)
	{
		num[x]=j;
		dfs(x+1);
	}
}

int main()
{
	cin>>b;
	for(int i=1;i<=b;i++)
	{
		cin>>p[i].c>>p[i].k>>p[i].p;
		pos[p[i].c]=i;
	}
	cin>>s;
	for(int i=1;i<=s;i++)
	{
		int t;
		cin>>t;
		for(int j=1;j<=t;j++)
		{
			int cc,kk;
			cin>>cc>>kk;
			zuhe[i][pos[cc]]=kk;
		}
		cin>>zuhe[i][0];
	}
	
	dfs(1);
	cout << cost[num[1]][num[2]][num[3]][num[4]][num[5]];
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值