问题 A: 斜线最大最小值
[命题人 : 201501010119]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
求如图所示一个上三角矩阵中每一条斜线中的最大元素(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;
const int N = 5500;
int main() {
int n;
while (cin >> n) {
vector<vector<int>> a(n, vector<int>(n));
vector<int> L(n), S(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> a[i][j];
}
}
for (int r = 1; r <= n; r++) {
L[r - 1] = a[0][r - 1];
S[r - 1] = a[0][r - 1];
for (int p = 1; p <= n - r; p++) {
int q = r - 1 + p;
if (a[p][q] > L[r - 1]) {
L[r - 1] = a[p][q];
}
if (a[p][q] < S[r - 1]) {
S[r - 1] = a[p][q];
}
}
}
for (int k = 0; k < n; k++) {
cout << "L" << k + 1 << "=" << L[k] << ", S" << k + 1 << "=" << S[k] << endl;
}
}
return 0;
}
问题 C: 矩阵连乘问题-动态规划求最优值
[命题人 : 201501010119]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
使用动态规划算法求解矩阵连乘问题,输出最少乘法次数。
输入
每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。
输出
矩阵连乘最优计算次数。
样例输入 Copy
7 30 35 15 5 10 20 25
样例输出 Copy
15125
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
int a[maxn], dp[maxn][maxn];
int main() {
int n;
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]); memset(dp, 0, sizeof(dp));
for (int r = 2; r <= n; ++r) {
for (int i = 1; i <= n - r + 1; ++i) {
int j = i + r - 1;
dp[i][j] = dp[i + 1][j] + a[i] * a[i + 1] * a[j + 1];
for (int k = i + 1; k < j; ++k)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i] * a[k + 1] * a[j + 1]);
}
}
printf("%d\n", dp[1][n - 1]);
}
return 0;
}
问题 D: 矩阵连乘问题-构造最优解
[命题人 : 201501010119]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
使用动态规划算法求解矩阵连乘问题。
输入
每组数据包括两行,第一行为数组长度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;
const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int a[maxn], dp[maxn][maxn], s[maxn][maxn];
void solve(int l, int r) {
if (s[l][r])
{
solve(l, s[l][r]);
solve(s[l][r], r);
printf("A[%d:%d] * A[%d:%d]\n", l, s[l][r] - 1, s[l][r], r - 1);
}
}
int main() {
int n;
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
memset(dp, 0, sizeof(dp));
for (int l = 2; l <= n; ++l) {
for (int i = 1; i + l <= n; ++i) {
int j = i + l; dp[i][j] = inf;
for (int k = i + 1; k < j; ++k) {
int x = dp[i][k] + dp[k][j] + a[i] * a[k] * a[j];
if (dp[i][j] > x) {
dp[i][j] = x;
s[i][j] = k;
}
}
}
}
solve(1, n);
}
return 0;
}
问题 E: 石子合并问题
[命题人 : 201501010119]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
在一条直线上有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;
const int maxn = 250;
const int INF = 0x7fffff;
int n;
int S[maxn];
int sum[maxn][maxn];
int dp[maxn][maxn];
int main()
{
while (~scanf("%d", &n))
{
for (int i = 1; i <= n; i++)
scanf("%d", &S[i]), sum[i][i] = S[i];
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
dp[i][j] = (i == j ? 0 : INF);
for (int len = 1; len < n; len++)
{
for (int i = 1; i + len <= n; i++)
{
int j = i + len;
for (int k = i; k < j; k++)
{
sum[i][j] = sum[i][k] + sum[k + 1][j];
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[i][j]);
}
}
}
cout << dp[1][n] << endl;
cout << endl;
}
return 0;
}
问题 F: X星人的基因
[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
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;
int dp[1050][1050];
const int N = 1e6+10;
char a[N],b[N];
int main(){
int n;
while(cin >> n && n != 0){
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++){
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]);
}
}
}
double ans = (dp[n][n] - 1) * 1.0 / n;
cout << ans << endl;
if(ans <= 0.5){
cout << "YES" << endl;
}else cout << "NO" <<endl;
}
return 0;
}
问题 G: 路径统计
[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
小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
但是这个只过了27%,不知道为啥,用dfs又超时了
#include<bits/stdc++.h>
using namespace std;
int dp[105][105];
const int mod = 1e9+7;
int main(){
int n,m,x,y;
cin >> n >> m >> x >> y;
for(int i = 1;i <= n;i++)dp[i][m] = 1;
for(int i = 1;i <= m;i++)dp[1][i] = 1;
for(int i = 2;i <= n;i++){
for(int j = m;j >= 1;j--){
if(i == x && j == y)continue;
dp[i][j] = (dp[i - 1][j] + dp[i][j + 1]) % mod;
}
}
cout << dp[n][1] << endl;
return 0;
}
//用的dfs方法
#include<bits/stdc++.h>
using namespace std;
bool vis[105][105];
int n,m,x,y;
int ans = 0;
const int mod = 1e9+7;
int a[105][105];
void dfs(int a,int b){
if(a == 1 && b == m)ans++,ans %= mod;
if(a < 1 || b < 1 || a > n || b > n || vis[a][b] == true)return;
dfs(a - 1,b);
dfs(a,b + 1);
}
int main(){
cin >> n >> m >> x >> y;
memset(a,0,sizeof(a));
vis[x][y] = true;
dfs(n,1);
cout << ans << endl;
return 0;
}
问题 H: 删数问题
[命题人 : admin]
时间限制 : 1.000 sec 内存限制 : 128 MB
提交问题列表
题目描述
在一个数列中有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 <iostream>
#include <vector>
#include <algorithm>
int main() {
int n;
std::cin >> n;
std::vector<int> exp(n);
for (int i = 0; i < n; i++) {
std::cin >> exp[i];
}
std::vector<int> arr;
int k = 0;
for (int i = 0; i < n; i++) {
int x = exp[i];
if (k == 0 || x > arr.back()) {
arr.push_back(x);
k++;
} else {
auto it = std::lower_bound(arr.begin(), arr.end(), x);
if (it != arr.end()) {
*it = x;
} else {
arr.push_back(x);
k++;
}
}
}
std::cout << k << std::endl;
return 0;
}