中国矿业大学算法导论-作业1-赵莹

问题 A: algorithm-锯木棒

题目描述

xiaok大佬最近再雇佣工人给他掰木棒。把一根长为L的木棒锯成两段,他需要支付给工人L元钱。xiaok大佬一开始只有长为L的一根木棒,他想把它锯成n段,每段长度分别为L1,L2,...,Ln,问xiaok大佬最少要付给工人多少钱?

输入

第一行两个整数n,L(1<n<103,n<L<109)
第二行n个整数L1,L2,...,Ln(0<Li<L,且保证L1+L2+...+Ln=L)

输出

输出一个整数,表示最小花费

样例输入 Copy
3 21
8 5 8
样例输出 Copy
34

倒着做,贪心

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=1e3+10;
int n,len;
int q[N];
int main(){
	priority_queue<int,vector<int>, greater<int> > qu;
	scanf("%d%d",&n,&len);
	long long cost=0;
	for(int i=0;i<n;i++) {
		int temp;
		scanf("%d",&temp);
		qu.push(temp);
	}
	while(qu.size()>1){
		int a=qu.top();
		qu.pop();
		int b=qu.top();
		qu.pop();
		int sum=a+b;
		cost+=sum;
		qu.push(sum);
	}
	
	printf("%lld",cost);
}

问题 B: algorithm-最长公共子序列

题目描述

一个字符串A的子串被定义成从A中顺次选出若干个字符构成的串。如A=“cdaad" ,顺次选1,3,5个字符就构成子串" cad" ,现给定两个字符串,求它们的最长共公子串。

输入

第一行两个字符串用空格分开。两个串的长度均小于2000 。

输出

最长子串的长度。

样例输入 Copy
abccd aecd
样例输出 Copy
3

dp板子题

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N=2010;
char a[N],b[N];
int f[N][N];
int main(){
	scanf("%s%s",a+1,b+1);
	int n=strlen(a+1);
	int m=strlen(b+1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			f[i][j]=max(f[i-1][j],f[i][j-1]);
			if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
		}
	}

	printf("%d",f[n][m]);
	return 0;
}

问题 C: algorithm-矩阵连乘

题目描述
给定n个矩阵{A1,A2,...,An},及m个矩阵连乘的表达式,判断每个矩阵连乘表达式是否满足矩阵乘法法则,如果满足,则计算矩阵的最小连乘次数,如果不满足输出“MengMengDa“。
输入
输入数据由多组数据组成(不超过10组样例)。每组数据格式如下:
第一行是2个整数n (1≤n≤26)和m(1≤m≤3),表示矩阵的个数。
接下来n行,每行有一个大写字母,表示矩阵的名字,后面有两个整数r和c,分别表示该矩阵的行数和列数,其中1<r, c<100。
第n+1行到第n+m行,每行是一个矩阵连乘的表达式(2<=矩阵个数<=100)。
输出

对于每个矩阵连乘表达式,如果运算不满足矩阵乘法法则的情况(即左矩阵列数与右矩阵的行数不同),则输出“MengMengDa”,否则输出最小矩阵连乘次数。

数据保证结果不超过1e9。

样例输入 Copy
3 2
A 10 100
B 5 50
C 100 5
ACB
ABC
样例输出 Copy
7500
MengMengDa

需要注意的是多组样例输入,乘法表达式长度和总矩阵个数不一致

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N=1050;
typedef pair<int,int>  PII;
PII q[N];
long long f[N][N];
int inde[N];
char matrix[N];
int n,m;
bool testValid(string a,int m){
    int i=0;
    int pre =-1;
    while(i<=m){
        for(int j=1;j<=n;j++){
             if(a[i]==matrix[j]){
                 if(pre == -1){
                     pre=q[j].second;
                     break;
                 }
                 if(pre!=q[j].first){
                     printf("MengMengDa\n");
                     return false;
                }
                pre=q[j].second;
            }
        }
        i++;
    }
    return true;        
}

int getMul(int l,int k,int r){
    return q[l].first*q[k].second*q[r].second;
}

void dp(string a,int m){
    for(int i=0;i<m;i++)
        for(int j=1;j<=n;j++)
            if(a[i]==matrix[j]) {
                inde[i+1]=j;
                break;
            }
    
    //for(int i=1;i<=m;i++) cout<<index[i]<<" "<<endl;
    
    for(int s=2;s<=m;s++){
        for(int l=1;l+s-1<=m;l++){
            int r=l+s-1;
            f[l][r]=1e8; 
            for(int k=l;k<r;k++){
                f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+getMul(inde[l],inde[k],inde[r]));
                //cout<<getMul(index[l],index[r])<<" "; 
            }
        }
    }
  /*  for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++) printf("%d ",f[i][j]);
        cout<<endl;
    }
        */
    printf("%d\n",f[1][m]);

}
int main(){
    while(scanf("%d %d",&n,&m)==2){
        for(int i=1;i<=n;i++){
            scanf("%s%d%d",&matrix[i],&q[i].first,&q[i].second);
        }
    
        while(m--){
            char tmp[110];
            scanf("%s",tmp);
            if(testValid(tmp,strlen(tmp))) dp(tmp,strlen(tmp));
        }
    }
    
    return 0;
}

问题 D: algorithm-沙子的质量

题目描述

设有N堆沙子排成一排,其编号为1,2,3,…,N(N< =300)。每堆沙子有一定的数量,可以用一个整数来描述,现在要将N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为1 3 5 2我们可以先合并1、2堆,代价为4,得到4 5 2又合并1,2堆,代价为9,得到9 2,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总的代价最小。输出最小代价。

输入

第一行一个数N表示沙子的堆数N。 第二行N个数,表示每堆沙子的质量。 a[i]< =1000。

输出

合并的最小代价。

样例输入 Copy
4
1 3 5 2
样例输出 Copy
22

dp板子题

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e3;
int q[N],f[N][N];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&q[i]);
		q[i]+=q[i-1];
	}
	for(int s=2;s<=n;s++){
		for(int l=1;l+s-1<=n;l++){
			int r=l+s-1;
			f[l][r]=1e8;
			for(int k=l;k<r;k++){	
				f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+q[r]-q[l-1]);
			}
		}
	}
	printf("%d",f[1][n]);
}

问题 E: algorithm-求第k小

题目描述

给定n(1<=n<=1000000)个元素,求第k小数(1<=k<=n)。

输入

一组样例。第一行输入两个整数n和k。第二行输入n个不同的int范围内的数。
 

输出

输出一行,输出第k小数。

样例输入 Copy
5 2
1 5 3 2 4
样例输出 Copy
2

快排变式

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,k,ans;
int q[N];
void quick_sort(int q[],int l,int r,int k){
	if(l==r){
		ans=q[l];
		return ;
	}
	if(l>r) return ;
 	int x=q[(l+r)>>1],i=l-1,j=r+1;
	while(i<j){
		do i++ ; while(q[i]<x);
		do j-- ; while(q[j]>x);
		if(i<j) swap(q[i],q[j]);
	}
	if(j-l+1>=k)quick_sort(q,l,j,k);
	else quick_sort(q,j+1,r,k-(j-l+1));
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++) scanf("%d",&q[i]);
	quick_sort(q,0,n-1,k);
	printf("%d",ans);
}

问题 F: algorithm-快速幂

题目描述



给定x,求f(x)对100000007取余的结果

输入
多组测试样例,最多50组。每组测试样例给定一个整数x(1<=x<=25000)
输出

对每个样例,输出一行,代表f(x)对100000007取余的结果。

样例输入 Copy
3
4
5
样例输出 Copy
33
289
3414

沾点数学知识,二进制优化

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=3e4;
int x,id;
long long q[N];
long long qmi(long long a){
	int b=a;
	long long ans=1;
	while(b){
		if(b&1) ans=(ans*a)%100000007;
		b=b>>1;
		a=(a*a)%100000007;
	}
	
	return ans;
}
int quickPower(int x){
	if(x<=id) return q[x];
	else{
		for(int i=id;i<=x;i++){
			q[i]=(q[i-1]+qmi(i))%100000007;
		}
	}
	id=x;
	return q[x];
}
int main(){
	while(scanf("%d",&x)==1){
		long long ans=quickPower(x);
		printf("%d\n",ans);
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值