A:斜线最大最小值
求如图所示一个上三角矩阵中每一条斜线中的最大元素(L)和最小元素(S)。
输入
每组输入包括两部分,一部分为数字n,表示三角矩阵的行数。
第二部分即为三角矩阵。输出
每一个对角线输出一行,每行包括Lx=Max, Sx=Min,其中x为斜线序号(序号从1开始),Max为该斜线上的最大值,Min为该斜线上的最小值。
样例输入 Copy
6 1 3 5 7 11 20 0 6 8 2 3 13 0 0 7 4 8 9 0 0 0 18 3 10 0 0 0 0 12 6 0 0 0 0 0 15样例输出 Copy
L1=18, S1=1 L2=8, S2=3 L3=10, S3=2 L4=9, S4=3 L5=13, S5=11 L6=20, S6=20
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int a[N][N];
void solve(){
int n;
while(cin>>n){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
}
}
int m,mm;
for(int i=0;i<n;i++){
m=mm=a[0][i];
for(int j=1;j<n-i;j++){
m=max(a[j][i+j],m);
mm=min(a[j][i+j],mm);
}
cout<<'L'<<i+1<<'='<<m<<", S"<<i+1<<'='<<mm<<"\n";
}
}
}
int main() {
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}
B:矩阵连乘问题-备忘录法求最优值
题目描述
使用备忘录法求解矩阵连乘问题,输出最少乘法次数。
输入
每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。
输出
矩阵连乘最优计算次数。
样例输入 Copy
7 30 35 15 5 10 20 25样例输出 Copy
15125
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int n;
int a[N];
int b[N][N];
int fun(int i,int j) {
if(b[i][j]){
return b[i][j];
}
if(i==j){
return 0;
}
else{
int u=fun(i+1,j)+a[i-1]*a[i]*a[j];
for(int k=i+1;k<j;k++){
int t=fun(i,k)+fun(k+1,j)+a[i-1]*a[k]*a[j];
if(t<u){
u=t;
}
}
b[i][j]=u;
}
return b[i][j];
}
void solve(){
while(cin>>n){
memset(b,0,sizeof b);
for(int i=0;i<n;i++){
cin>>a[i];
}
cout<<fun(1,n-1)<<"\n";
}
}
int main(){
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}
C:矩阵连乘问题-动态规划求最优值
题目描述
使用动态规划算法求解矩阵连乘问题,输出最少乘法次数。
输入
每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。
输出
矩阵连乘最优计算次数。
样例输入 Copy
7 30 35 15 5 10 20 25样例输出 Copy
15125
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int n;
int a[N];
int b[N][N];
void solve(){
while(cin>>n){
memset(b,0,sizeof b);
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int l=2;l<n;l++){
for(int i=1;i<n-l+1;i++){
int j=i+l-1;
b[i][j]=b[i+1][j]+a[i+1]*a[i]*a[j+1];
for(int k=i+1;k<j;k++){
b[i][j]=min(b[i][k]+b[k+1][j]+a[i]*a[k+1]*a[j+1],b[i][j]);
}
}
}
cout<<b[1][n-1]<<"\n";
}
}
int main(){
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}
D:矩阵连乘问题-构造最优解
题目描述
使用动态规划算法求解矩阵连乘问题。
输入
每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。
输出
矩阵连乘最优计算次序。
样例输入 Copy
7 30 35 15 5 10 20 25样例输出 Copy
A[2:2] * A[3:3] A[1:1] * A[2:3] A[4:4] * A[5:5] A[4:5] * A[6:6] A[1:3] * A[4:6]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int a[N];
int b[N][N],s[N][N];
void fun(int l,int r){
if(s[l][r]){
fun(l,s[l][r]);
fun(s[l][r],r);
cout<<"A["<<l<<":"<<s[l][r]-1<<"] * A["<<s[l][r]<<":"<<r-1<<"]\n";
}
}
void solve(){
int n;
while(cin>>n){
memset(b,0,sizeof b);
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int l=2;l<n;l++){
for(int i=1;i<=n-l;i++){
int j=i+l;
b[i][j]=inf;
for(int k=i+1;k<j;k++){
int m=b[i][k]+b[k][j]+a[i]*a[k]*a[j];
if(b[i][j]>m){
b[i][j]=m;
s[i][j]=k;
}
}
}
}
fun(1,n);
}
}
int main(){
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}
E:石子合并问题
题目描述
在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。例如:输入{1,2,3,4,5},输出33。【3+6+9+15=33】
输入
本题应该处理到文件尾,每组输入包括两行,第一行为石子堆的个数n,第二行则为每堆石子的个数。
输出
输出最小花费。
样例输入 Copy
5 1 2 3 4 5样例输出 Copy
33
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int a[N],s[N],dp[N][N];
void solve(){
int n;
while(cin>>n){
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int l=2;l<=n;l++){
for(int i=1;i+l-1<=n;i++){
int j=i+l-1;
dp[i][j]=inf;
int x=s[j]-s[i-1];
for(int k=i;k<j;k++){
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+x);
}
}
}
cout<<dp[1][n]<<"\n";
}
}
int main() {
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}
F:X星人的基因
题目描述
X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列为M,则相似度=M/N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?输入
每一组测试数据包含3行,
第1行数字N表示待比较基因序列片段的长度,N<=10^3。
第2行和第3行为两个长度为N的基因序列片段。
输入0表示结束。输出
两个X星人是否可以结婚,如果可以输出”Yes“,如果不可以输出”No“。
样例输入 Copy
8 A B C D E A B C A C C D C B A E 6 A B C D E E A E D C B B 0样例输出 Copy
Yes Yes
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 +5;
const int M = 1e9 +7;
char a[N],b[N];
double dp[N][N];
void solve(){
double n;
while(cin>>n&&n){
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
if(a[i]==b[j]){
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
}
}
}
int s=n;
if(dp[s][s]/n>0.5){
cout<<"No\n";
}
else{
cout<<"Yes\n";
}
}
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
solve();
return 0;
}
G:路径统计
题目描述
小Z住在一个建筑物很整齐的矩形小区的左下角,学校在小区右上角。
小Z和学校之间有M条东西向的道路,有N条南北向的道路。小Z的爸爸每天早上开车送他上学,但是这些道路都是单行线,只能朝北走或者朝东走。
由于道路施工,在某个路口现在有一个警示桩,表示此处暂不能通行。
现在告诉你M和N的值,以及警示桩的位置,请你统计从小Z家到学校有多少条不同的路径(答案对1e9+7取模)?
下图是当M=4,N=4,在从左到右第2条南北方向的道路和从上至下第2条东西方向的道路的交叉口有一个警示桩的示意图。
输入
单组输入。
第1行输入两个正整数M和N,分别表示东西向道路和南北向道路的数量,M和N均不超过100,两者之间用英文空格隔开。
第2行输入两个正整数X和Y,表示警示桩的位置,X表示从左到右第X条南北方向的道路,Y表示从上至下第Y条东西方向的道路。(1<=X<=N,1<=Y<=M)输出
输出从小Z家到学校的不同路径条数(答案对1e9+7取模)。
样例输入 Copy
4 4 2 2样例输出 Copy
11
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
ll a[105][105];
void solve(){
int m, n, x, y;
cin >> m >> n >> x >> y;
a[m][0] = 1;
for (int i = m; i >=1; i--)
for (int j = 1; j <= n; j++)
{
if (i == y && j == x)
a[i][j] = 0;
else
a[i][j] = a[i + 1][j]%M + a[i][j - 1]%M;
}
cout << a[1][n]%M << "\n";
}
int main() {
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}
H:删数问题
题目描述
在一个数列中有N个正整数,现在需要对这个数列进行若干趟删数操作。
每趟删数操作的规则和要求说明如下:
(1) 一趟删数操作包含1次或多次删除操作,每次删除操作均需要删除一个数。
(2) 下一个要删除的数的下标必须大于上一个删除的数。
(3) 下一个要删除的数的值不能大于上一个删除的数。
通过M趟删数操作后正好将数列中所有数字全部都删除完毕。
请问M的最小值为多少?即最少需要多少趟删数操作才可以将数列清空?输入
单组输入。
第1行输入一个正整数N,表示数列中数字的总个数。(N<=10^3)
第2行输入N个正整数,两两之间用空格隔开。输出
输出M的最小值,即最少需要多少趟删数操作才能将数列清空。
样例输入 Copy
8 1 5 5 4 3 4 6 2样例输出 Copy
4
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
void solve(){
int n;
cin>>n;
vector<int> a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
int s=0;
while(!a.empty()){
int t=a[0];
a.erase(a.begin());
for(int i=0;i<a.size();){
if(a[i]<=t){
t=a[i];
a.erase(a.begin()+i);
}
else{
i++;
}
}
s++;
}
cout<<s<<"\n";
}
int main() {
cin.tie(0)->sync_with_stdio(false);
solve();
return 0;
}