最长公共子序列
【问题描述】给定两个字符串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;
string a,b;
//求长度
int LCS_length(string a,string b)
{
int n=a.length(),m=b.length();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i-1]==b[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
return dp[n][m];
}
//求序列
void LCS(string a,string b,int i,int j)
{
if(i==0||j==0) return;
if(a[i-1]==b[j-1])
{
LCS(a,b,i-1,j-1);
cout<<a[i-1];
}
else if(dp[i-1][j]>dp[i][j-1]) LCS(a,b,i-1,j);
else LCS(a,b,i,j-1);
}
int main()
{
cin>>a>>b;
cout<<LCS_length(a,b)<<endl;
LCS(a,b,a.length(),b.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
d=1 | d=2 | d=3 | d=4 | d=5 |
m(1,1) | m(1,2) | m(1,3) | m(1,4) | m(1,5) |
m(2,2) | m(2,3) | m(2,4) | m(2,5) | |
m(3,3) | m(3,4) | m(3,5) | ||
m(4,4) | m(4,5) | |||
m(5,5) |
#include<bits/stdc++.h>
using namespace std;
int n,a[1000];
int m[1000][1000];//从矩阵i乘到矩阵j的最小数乘次数
int s[1000][1000];//i到j之间哪个中转站使m(i,j)最小
void Print(int i,int j)
{
if(i==j) cout<<'M'<<i;
else
{
cout<<'(';
Print(i,s[i][j]);
Print(s[i][j],j);
cout<<')';
}
}
int main()
{
cin>>n;
for(int i=0;i<2*n;i++)
{
int x;
cin>>x;
a[i/2+1]=x;
}
for(int d=2;d<=n;d++)//d个矩阵相乘
{
for(int i=1;i<=n-d+1;i++)//斜着有i个m(i,j)
{
int j=i+d-1;
m[i][j]=9999;
for(int k=i;k<=i+d-2;k++)//从i到j中间k位置断开
{
int temp=m[i][k]+m[k+1][j]+a[i]*a[k+1]*a[j+1];
if(temp<m[i][j])
{
m[i][j]=temp;
s[i][j]=k;
}
}
}
}
cout<<m[1][n]<<endl;
Print(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;
int n,m;
int dist[1000][1000];
int main()
{
cin>>n>>m;
memset(dist,0x3f3f3f3f,sizeof(dist));
for(int i=1;i<=n;i++)
{
dist[i][i]=0;
}
for(int i=1;i<=m;i++)
{
int x,y,w;
cin>>x>>y>>w;
dist[x][y]=w;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
dist[j][k]=min(dist[j][k],dist[j][i]+dist[i][k]);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<dist[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
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;
int c,n;
int s[1000],v[1000];
int dp[1000][1000];
int main()
{
cin>>c>>n;
for(int i=1;i<=n;i++) cin>>s[i]>>v[i];
for(int i=1;i<=n;i++)//装入第i件物品
{
for(int j=1;j<=c;j++)//剩余体积
{
if(j>=s[i]) dp[i][j]=max(dp[i-1][j],dp[i-1][j-s[i]]+v[i]);
else dp[i][j]=dp[i-1][j];
}
}
cout<<dp[n][c];
return 0;
}
最少费用购物
问题描述:
商店中每种商品都有标价。例如,一朵花的价格是2 元。一个花瓶的价格是5 元。为了吸引顾客,商店提供了一组优惠商品价。优惠商品是把一种或多种商品分成一组,并降价销售。例如,3 朵花的价格不是6 元而是5 元。2 个花瓶加1 朵花的优惠价是10 元。试设计一个算法,计算出某一顾客所购商品应付的最少费用。
编程任务:
对于给定欲购商品的价格和数量,以及优惠商品价,编程计算所购商品应付的最少费用。
数据输入:
欲购商品数据:第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 件商品。
优惠商品价数据:第1 行中有1 个整数S(0≤S≤99),表示共有S 种优惠商品组合。接下来的S 行,每行的第一个数描述优惠商品组合中商品的种类数j。接着是j 个数字对(C,K),其中C 是商品编码,1≤C≤999。K 表示该种商品在此组合中的数量,1≤K≤5。每行最后一个数字P(1≤ P≤9999 )表示此商品组合的优惠价。
结果输出:
程序运行结束时,输出所购商品应付的最少费用。
输入示例 输出示例
2 2 14
7 3 2 1 7 3 5
8 2 5 2 7 1 8 2 10
#include<bits/stdc++.h>
using namespace std;
struct com{
int price;//优惠组合的价格
int k[1000];//编号为j的商品数量
}zh[1000];//第i种优惠组合
int cost[6][6][6][6][6];
int num[1000];//商品编号
int p[1000];//编号为i的商品的单价
int k[1000];//编号为i的商品的需要数量
int b,s;//b种商品,s种组合
int main()
{
//预购商品信息
cin>>b;
for(int i=1;i<=b;i++)
{
cin>>num[i];
int temp=num[i];
cin>>k[temp]>>p[temp];
}
//优惠组合信息
cin>>s;
for(int i=1;i<=s;i++)
{
int x;
cin>>x;
for(int j=1;j<=x;j++)
{
int tmp;
cin>>tmp;
cin>>zh[i].k[tmp];
}
cin>>zh[i].price;
}
cost[0][0][0][0][0]=0;
for(int i=0;i<=k[num[1]];i++)
{
for(int j=0;j<=k[num[2]];j++)
{
for(int l=0;l<=k[num[3]];l++)
{
for(int m=0;m<=k[num[4]];m++)
{
for(int n=0;n<=k[num[5]];n++)
{
//不使用优惠组合的价格
int minm=i*p[num[1]]+j*p[num[2]]+l*p[num[3]]+m*p[num[4]]+n*p[num[5]];
for(int g=1;g<=s;g++)//使用优惠组合
{
if(i<zh[g].k[num[1]]||j<zh[g].k[num[2]]||l<zh[g].k[num[3]]
||m<zh[g].k[num[4]]||n<zh[g].k[num[5]])
continue;
int t=cost[i-zh[g].k[num[1]]][j-zh[g].k[num[2]]][l-zh[g].k[num[3]]]
[m-zh[g].k[num[4]]][n-zh[g].k[num[5]]]+zh[g].price;
if(t<minm) minm=t;
}
cost[i][j][l][m][n]=minm;
}
}
}
}
}
cout<<cost[k[num[1]]][k[num[2]]][k[num[3]]][k[num[4]]][k[num[5]]];
return 0;
}