搜索
您的当前位置:首页正文

OpenJudge算法设计与分析习题解答

来源:小奈知识网
1、硬币面值组合

描述

使用1角、2角、5角硬币组成 n 角钱。

设1角、2角、5角的硬币各用了a、b、c个,列出所有可能的a, b, c组合。 输出顺序为:先按c的值从小到大,若c相同则按b的值从小到大。

输入

一个整数n(1 <= n <= 100),代表需要组成的钱的角数。

输出

输出有若干行,每行的形式为: i a b c

第1列i代表当前行数(行数从001开始,固定3个字符宽度,宽度不足3的用0填充),后面3列a, b, c分别代表1角、2角、5角硬币的个数(每个数字固定12个字符宽度,宽度不足的在左边填充空格)。

样例输入

10 样例输出 001 10 0 0 002 8 1 0 003 6 2 0 004 4 3 0 005 2 4 0 006 0 5 0 007 5 0 1 008 3 1 1 009 1 2 1 010 0 0 2 源代码:

#include

#include int main(){ }

int t=1; int i,j,k; int n;

scanf(\"%d\int A=n,B=n/2,C=n/5; for(i=0;i<=C;i++){

for(j=0;j<=B;j++){

for(k=0;k<=A;k++){

if(i*5+j*2+k*1==n){

printf(\"%03d%12d%12d%12d\\n++;

}

}

}

}

getchar(); return 0;

2、比赛排名

描述

5名运动员参加100米赛跑,各自对比赛结果进行了预测: A说:E是第1名。 B说:我是第2名。 C说:A肯定垫底。

D说:C肯定拿不了第1名。 E说:D应该是第1名。

比赛结束后发现,只有获第1名和第2名的选手猜对了,E不是第2名和第3名,没有出现名次并列的情况。

请编程判断5位选手各是第几名。

输入

输出

输出要求:按ABCDE的顺序输出5行,其中第1行是A的名次,第2行是B的名次, 第3行是C的名次,第4行是D的名次,第5行是E的名次。

样例输入 样例输出

源代码:

#include int main() {

printf(\"5\\n\"); printf(\"2\\n\"); printf(\"1\\n\"); printf(\"3\\n\"); printf(\"4\\n\"); return 0; }

3、鸡兔同笼

描述

一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物。

输入

一行,一个正整数a (a < 32768)。

输出

一行,包含两个正整数,第一个是最少的动物数,第二个是最多的动物数,两个正整数用一个空格分开。

如果没有满足要求的答案,则输出两个0,中间用一个空格分开。

样例输入 20 样例输出 5 10 源代码:

#include int main() {

int n; scanf(\"%d\if(n % 4== 0)

printf(\"%d %d\else if(n % 4!= 0&&n % 2== 0) printf(\"%d %d\

else

printf(\"0 0\"); return 0; }

4、谁是你的潜在朋友

描述

“臭味相投”——这是我们描述朋友时喜欢用的词汇。两个人是朋友通常意味着他们存在着许多共同的兴趣。然而作为一个宅男,你发现自己与他人相互了解的机会并不太多。幸运的是,你意外得到了一份北大图书馆的图书借阅记录,于是你挑灯熬夜地编程,想从中发现潜在的朋友。

首先你对借阅记录进行了一番整理,把N个读者依次编号为1,2,…,N,把M本书依次编号为1,2,…,M。同时,按照“臭味相投”的原则,和你喜欢读同一本书的人,就是你的潜在朋友。你现在的任务是从这份借阅记录中计算出每个人有几个潜在朋友。

输入

第一行两个整数N,M,2 <= N ,M<= 200。接下来有N行,第i(i = 1,2,…,N)行每一行有一个数,表示读者i-1最喜欢的图书的编号P(1<=P<=M)

输出

包括N行,每行一个数,第i行的数表示读者i有几个潜在朋友。如果i和任何人都没有共同喜欢的书,则输出“BeiJu”(即悲剧,^ ^)

样例输入 4 5 2 3 2 1 样例输出 1 BeiJu 1 BeiJu 源代码:

#include #include int b[ 222 ]; int a[ 222 ]; int n, m; int main() {

scanf(\"%d%d\ for(int i = 1; i <= n; i++ ){ scanf(\"%d\ b[ a[ i ] ]++; }

for( int i = 1; i <= n; i++ ){ if( b[ a[ i ] ] == 1 ) printf(\"BeiJu\\n\"); else if( b[ a[ i ]] >= 2 )

printf(\"%d\\n\ } return 0; }

5、称体重

描述

、钱、、四个人中既有大人也有小孩,给他们称体重时发现,他们每个人的体重都不一样,且体重(单位:公斤)恰好是10的整数倍,且他们的体重都不高 于50公斤,已知、钱两人的体重之和恰好等于、两人的体重之和;、两人的体重之和大于、钱两人的体重之和,并且、俩人的体重之和还小于钱的体重。请编写一个程序,按照体重从小到大的顺序,打印出四人的姓氏的首字母和体重数。

输入

输出

打印出四人的姓氏的首字母(小写)和体重数(每人一行,首字母和体重数之间用空格隔开)。

样例输入 无 样例输出 z 10 q 20 s 30 l 40 (以上输出仅用于说明格式) #include #include int main(){

int a[4],b[4]={1,2,3,4},c[4]={'z','q','s','l'}; int i,j,t;

for(a[0]=1;a[0]<=5;a[0]++){

for(a[1]=1;a[1]<=5;a[1]++){

for(a[2]=1;a[2]<=5;a[2]++){

for(a[3]=1;a[3]<=5;a[3]++){

if((a[1]!=a[0]&&a[2]!=a[1]&&a[2]!=a[0]&&a[3]!=a[2]&&a[3]!=a[1]&&a[3]!=a[0])

&&(a[0]+a[1]==a[2]+a[3])&&(a[0]+a[3]>a[1]+a[2])&&(a[0]+a[2]for(i=0;i<4;i++){

a[i]=b[i]; }

}

for(i=0;i<4;i++){

b[i]=a[i];

}

} }

}

for(i=0;i<4;i++){

for(j=i+1;j<4;j++){ if(b[i]>b[j]){ t=b[i]; b[i]=b[j]; b[j]=t; } } }

for(j=0;j<4;j++){

}

}

for(i=0;i<4;i++){ }

if(a[i]==b[j]){ }

printf(\"%c %d\\n\

getchar(); return 0;

6、比饭量

描述

3个人比饭量,每人说了两句话:

A说:B比我吃的多,C和我吃的一样多 B说:A比我吃的多,A也比C吃的多 C说:我比B吃得多,B比A吃的多。

事实上,饭量和正确断言的个数是反序的关系。 请编程按饭量的大小输出3个人的顺序。

输入

无输入

输出

按照饭量大小输出3人顺序,比如: ABC

样例输入

无 样例输出

无 #include #include int main(){ int A,B,C; int a,b,c; for(A=1;A<=3;A++){

for(B=1;B<=3;B++){

for(C=1;C<=3;C++){

a=((B>A)+(C==A)); b=((A>B)+(A>C)); c=((C>B)+(B>A));

if( ((A>B&&ab)) + ((A>C&&ac)) + ((Bc)||(B==C&&b==c)||(B>C&&bif(a>b&&a>c){ }

if(b>a&&b>c){ }

if(c>a&&c>b){

if(a>b) printf(\"CAB\"); if(a>c) printf(\"BAC\"); else printf(\"BCA\"); if(b>c) printf(\"ABC\"); else printf(\"ACB\");

}

else printf(\"CBA\");

}

}

}

}

getchar(); return 0; }

7、求排列的逆序数

描述

在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务。

对于不同的排名结果可以用逆序来评价它们之间的差异。考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。

一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序

(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

现给定1,2,…,n的一个排列,求它的逆序数。

输入

第一行是一个整数n,表示该排列有n个数(n <= 100000)。 第二行是n个不同的正整数,之间以空格隔开,表示该排列。

输出

输出该排列的逆序数。

样例输入

6 2 6 3 4 5 1 样例输出 8 提示

1. 利用二分归并排序算法(分治);

2. 注意结果可能超过int的围,需要用long long存储。 #include using namespace std;

const int MAX_NUM = 100000 + 5; long long seq[MAX_NUM]; int N; long long ans;

void reSeq(long long* seq, int lef, int righ) {//用long long存储,避免结果超过int的围

if(lef >= righ) { return ; }

int mid = lef + (righ - lef) / 2; reSeq(seq, lef, mid); reSeq(seq, mid + 1, righ);

int totalSize = righ - lef + 1; long long tmp[totalSize]; int n = lef; int m = mid + 1; int i = 0;

while(n <= mid || m <= righ) {

if(m > righ || (n <= mid && seq[n] <= seq[m])) { tmp[i++] = seq[n++]; } else {

tmp[i++] = seq[m++]; ans += mid - n + 1; } } i = lef;

for(int j = 0; j < totalSize; j++) { seq[i++] = tmp[j]; } }

void reSeqNum(long long* seq, int n) { reSeq(seq, 0, n - 1); }

int main() { scanf(\"%d\

for(int i = 0; i < N; i++) { scanf(\"%ld\ } ans = 0;

reSeqNum(seq, N); printf(\"%ld\\n\ return 0; }

8、Grey码

描述

Grey码是一个长度为2的序列,序列中无相同元素,且每个元素都是长度为n的二进制位

3

串,相邻元素恰好只有1位不同。例如长度为2的格雷码为

(000,001,011,010,110,111,101,100)。设计分治算法对任意的n值构造相应的Grey码。

n

输入

每个元素的长度值n。

输出

将所有相应的Grey码分行输出,即每一行输出一个二进制位串。

样例输入 3 样例输出 000 001 011 010 110 111 101 100 源代码:

#include #include int power(int base,int n) {

int i,p=1; for(i=1;i<=n;++i) p=p*base; return p; }

void Grey(int a,int b,int **arr,int k){

if(b==1){

*((int*)arr+k*0+0)=0; //arr[0][0]=0; *((int*)arr+k*1+0)=1; //arr[1][0]=1; return ;

}else{

for(int i=0;i*((int*)arr+k*i+b-1)=0; //arr[i][b-1]=0;

*((int*)arr+k*(a-i-1)+b-1)=1; //arr[a-i-1][b-1]=1;

}

}

Grey(a/2,b-1,(int **)arr,k); for(int i=a/2;ifor(int j=0;j*((int*)arr+k*i+j)=*((int*)arr+k*(a-i-1)+j); //arr[i][j]=arr[a-i-1][j];

}

}

int main(){ }

int n;

scanf(\"%d\int m=(int)power(2,n); int arr[m][n];

Grey(m,n,(int **)arr,n); for(int i=0;ifor(int j=n-1;j>=0;j--){ }

printf(\"\\n\");

printf(\"%d\

9、循环比赛

描述

设有N个选手的循环比赛。其中N=2^M(2的M次方),要求每名选手要与其他N-1名选手都赛一次,每名选手每天比赛一次,循环赛共进行N-1天,要求每天没有选手轮空。

输入

M

输出

表格形式的比赛安排表

样例输入 3 样例输出 1 2 3 4 5 6 7 8 2 1 4 3 6 5 8 7 3 4 1 2 7 8 5 6 4 3 2 1 8 7 6 5 5 6 7 8 1 2 3 4 6 5 8 7 2 1 4 3 7 8 5 6 3 4 1 2 8 7 6 5 4 3 2 1 提示

M的大小不会超过8 源代码:

#include #include

void arrange(int k,int **a,int n){

int t=1,temp=1; *((int*)a+k*0+0)=1;

}

//a[0][0]=1; while(t<=n){ }

for(int i=0;ifor(int i=0;ifor(int j=0;j*((int*)a+k*(i+temp)+j)=*((int*)a+k*i+j+temp); //a[i+temp][j]=a[i][j+temp];

*((int*)a+k*(i+temp)+j+temp)=*((int*)a+k*i+j); //a[i+temp][j+temp]=a[i][j]; for(int j=0;j*((int*)a+k*i+j+temp)=*((int*)a+k*i+j)+temp; //a[i][j+temp]=a[i][j]+temp;

int main(){ int n;

scanf(\"%d\int k=1;

for(int i=0;iint a[k][k];

k=2*k;

arrange(k,(int **)a,n); for(int i=0;i}

getchar(); return 0;

for(int j=0;jprintf(\"\\n\");

printf(\"%d\

10、棋盘覆盖问题

描述

在一个2×2个方格组成的棋盘中,若恰有一个方格与其他方格不同,称该方格为特殊方格,

kk

且称该棋盘为特殊棋盘。显然,特殊方格在棋盘中出现的位置有4种情形,因而有4种不同的棋盘,如图1所示是k=2时16种棋盘中的一个。在棋盘覆盖问题中,要求用图2所示的4种不同形状的L型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任何两个L型骨牌不得重叠覆盖。

k

k

输入

对每一个测试例有2行,第一行是k(1<=k<=10),第二行是特殊方格所在的位置坐标x,y(0<=x,y<1024)。

输出

边长为2的k次方的方阵,特殊方格的编号为0,所有L型骨牌从1开始编号,数据之间的间隔是空格。

样例输入

2 0 1 样例输出

2 0 3 3 2 2 1 3 4 1 1 5 4 4 5 5 提示

按分治策略进行算法设计。 #include #include int t=0;

int board[100][100];

void ChessBoard(int tr,int tc,int dr,int dc,int size){

int s,t1; if(size==1) return ; t1=++t;

s=size/2;

if(drChessBoard(tr,tc,dr,dc,s);

}else{ }

board[tr+s-1][tc+s-1]=t1;

ChessBoard(tr,tc,tr+s-1,tc+s-1,s);

if(dr=tc+s){

ChessBoard(tr,tc+s,dr,dc,s);

}else{ }

board[tr+s-1][tc+s]=t1;

ChessBoard(tr,tc+s,tr+s-1,tc+s,s);

if(dr>=tr+s&&dcChessBoard(tr+s,tc,dr,dc,s);

}else{ }

board[tr+s][tc+s-1]=t1;

ChessBoard(tr+s,tc,tr+s,tc+s-1,s);

if(dr>=tr+s&&dc>=tc+s){

ChessBoard(tr+s,tc+s,dr,dc,s);

}else{ }

board[tr+s][tc+s]=t1;

ChessBoard(tr+s,tc+s,tr+s,tc+s,s);

}

int main(){ int n,size=1; scanf(\"%d\ for(int i=0;i}

size=size*2;

int dr,dc;

scanf(\"%d%d\ ChessBoard(0,0,dr,dc,size); for(int i=0;i}

printf(\"\\n\");

printf(\"%d \

} }

getchar(); return 0;

11、输油管道问题

描述

某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n 口油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。如果给定n口油井的位置,即它们的x 坐标(东西向)和y 坐标(南北向),应如何确定主管道的最优位置,即使

各油井到主管道之间的输油管道长度总和最小的位置?证明可在线性时间确定主管道的最优位置。要求给定n口油井的位置,计算各油井到主管道之间的输油管道最小长度总和。

输入

由文件提供输入数据,文件第一行是油井数n,1<=n<=10000。接下来n行是油井的位置,每行两个整数x和y,-10000<=x,y<=10000。

输出

将结果输出到文件中,文件第一行中的数是油井到主管道之间的输油管道最小长度总和。

样例输入 5 1 2 2 2 1 3 3 -2 3 3 样例输出 6 提示

按分治策略进行算法设计。 源代码:

#include #include #include using namespace std; struct node {

int x,y;

} num[200000];

bool cmp(node a,node b) {

return a.yint main() {

int t;

scanf(\"%d\ int i,j; for(i=0;iscanf(\"%d%d\ } int ans;

sort(num,num+t,cmp); if(t%2==1) {

ans=0;

int zong=num[t/2].y; for(i=0;ians+=abs(num[i].y-zong); } }

else {

int zong=num[t/2].y+num[t/2-1].y; zong/=2; ans=0;

for(i=0;ians+=abs(num[i].y-zong); } }

printf(\"%d\\n\ return 0; }

12、0/1背包问题

描述

给定n种物品和一个背包,物品i(1≤i≤n)的重量是wi,其价值为vi,背包的容量为C,对每种物品只有两种选择:装入背包或者不装入背包。如何选择装入背包的物品,使得装入背包中物品的总价值最大?

输入

输入包含一组或多组测试例。每组测试例的第一行是物品的数量n和背包的容量C,之后的n行是每个物品的重量及其价值。

输出

输出第一行是装入背包中物品的总价值,后面n行是各个物品装入背包的情况。

样例输入

5 10 2 6 2 3 6 5 5 4 4 6 样例输出 15 1 1 0 0 1 源代码:

#include #include using namespace std; int dp[110][1010]; int n, c, ans[110]; int w[110], v[110]; void print(){

int i, j, k;

k=c;

for(i=n; i>=1; i--){

if(dp[i][k]!=dp[i-1][k]){

ans[i]=1; k=k-w[i];

}

}

} else{ }

return;

int main(){

int i, j, k;

scanf(\"%d%d\for(i=1; i<=n; i++){ }

for(i=1; i<=n; i++){ }

printf(\"%d\\n\print();

for(i=1; i<=n; i++) {

printf(\"%d\\n\for(j=1; j<=c; j++){ }

dp[i][j]=dp[i-1][j]; if(j>=w[i]){ }

dp[i][j]=max(dp[i-1][j-w[i]]+v[i], dp[i][j]);

scanf(\"%d%d\

}

} return 0;

13、最少硬币问题

描述

设有n种不同面值的硬币,各硬币的面值存于数组T[1:n]中。现要用这些面值的硬币来找钱。可以使用的各种面值的硬币个数存于数组Coins[1:n]中。对任意钱数0≤m≤20001,设计一个用最少硬币找钱m的方法。

对于给定的1≤n≤10,硬币面值数组T和可以使用的各种面值的硬币个数数组Coins,以及钱数m,0≤m≤20001,计算找钱m的最少硬币数。

输入

由文件提供输入数据,文件的第一行中只有1个整数给出n的值,第2行起每行2 个数,分别是T[j]和Coins[j]。最后1行是要找的钱数m。

输出

将计算出的最少硬币数输出到文件中。问题无解时输出-1。

样例输入 3 1 3 2 3 5 3 18 样例输出

5 提示

运用动态规划法进行算法设计并编程实现。 源代码:

#include #include using namespace std; int w[110], v[110]; int dp[110][20010]; int n, m; void init(){ }

int main(){

int i, j, k; int t, x,t=1; scanf(\"%d\for(i=1; i<=n; i++){ }

scanf(\"%d%d\for(j=1; j<=x; j++){ }

w[cnt]=t; v[cnt]=1; cnt++;

for(int i=0; i<110; i++){ }

for(int j=0; j<20010; j++){ }

dp[i][j]=2000000000;

}

scanf(\"%d\init();

for(i=0; ifor(i=1; iif(dp[cnt-1][m]==2000000000) printf(\"-1\"); else

printf(\"%d\return 0;

for(j=1; j<=m; j++){ }

dp[i][j]=dp[i-1][j];

if(j>=w[i]&&dp[i-1][j-w[i]]!=2000000000){ }

dp[i][j]=min(dp[i][j], dp[i-1][j-w[i]]+1);

//cnt++; dp[i][0]=0;

14、矩阵连乘

描述

给定n个矩阵{A1,A2,...,An},考察这n个矩阵的连乘积A1A2...An。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序,这种计算次序可以用加括号的方式来确定。

矩阵连乘积的计算次序与其计算量有密切关系。例如,考察计算3个矩阵{A1,A2,A3}连乘积的例子。设这3个矩阵的维数分别为10*100,100*5,和5*50。若按(A1A2)A3计算,3个矩阵连乘积需要的数乘次数为10*100*5+10*5*50 = 7500。若按A1(A2A3)计算,则总共需要100*5*50+10*100*50 = 75000次数乘。

现在你的任务是对于一个确定的矩阵连乘方案,计算其需要的数乘次数。

输入

输入数据由多组数据组成。每组数据格式如下:

第一行是一个整数n (1≤n≤26),表示矩阵的个数。

接下来n行,每行有一个大写字母,表示矩阵的名字,后面有两个整数a,b,分别表示该矩阵的行数和列数,其中1第n+1行是一个矩阵连乘的表达式,由括号与大写字母组成,没有乘号与多余的空格。如果表达式中没有括号则按照从左到右的顺序计算,输入的括号保证能够配对。

输出

对于每组数据,输出仅一行包含一个整数,即将该矩阵连乘方案需要的数乘次数。如果运算过程中出现不满足矩阵乘法法则的情况(即左矩阵列数与右矩阵的行数不同),则输出“error”。

样例输入

3 A 10 100 B 100 5 C 5 50 A(BC) 样例输出 75000 源代码:

# include # include # include # include # include

# include using namespace std; int n, ans; string exp, str; int x, y; struct node{ };

node s[200]; int flage; stack ope; stack v;

string change(string t){

int length=t.length(); string des=\"\";

for(int i=0; iif(isalpha(t[i])){ }

else if(t[i]=='('){

if(t[i+1]==')'){ } else{ }

des=des+t[i]+'*'; des=des+t[i];

int x,y;

}

}

}

des=des+t[i];

else{ }

if(t[i+1]==')'){ } else{ }

des=des+t[i]+'*'; des=des+t[i];

des=des+t[length-1]+'='; return des;

node calc(node a, node b){ }

char compare(char i, char j){

if(i=='='){ if(a.y!=b.x){ } node t;

ans=ans+a.x*a.y*b.y; t.x=a.x;t.y=b.y; return t;

flage=1;

}

}

if(j!='='){ } else{ }

return '='; return '<';

if(i=='('){ }

if(i=='*'){ }

if(j=='('){ } else{ }

return '>'; return '<'; if(j==')'){ } else{ }

return '<'; return '=';

int main(){

int i, j, k; string e; while(cin>>n){

for(i=1; i<=n; i++){ } cin>>e; flage=0; ans=0; exp=change(e); while(!ope.empty()){ }

while(!v.empty()){ }

ope.push('='); int l=exp.length(); for(k=0; k<=l-1; ){

if(isalpha(exp[k])){ }

v.push(s[exp[k]]); k++; v.pop(); ope.pop(); cin>>str>>x>>y; s[str[0]].x=x; s[str[0]].y=y;

}

}

else{ }

if(compare(ope.top(), exp[k])=='='){ }

else if(compare(ope.top(), exp[k])=='<'){ } else{ }

node a=v.top(); v.pop(); node b=v.top(); v.pop();

v.push(calc(b, a)); ope.pop(); ope.push(exp[k]); k++; ope.pop(); k++;

if(!flage) cout<cout<<\"error\"<return 0;

}

15、多边形游戏

描述

一个多边形,开始有n个顶点。每个顶点被赋予一个正整数值,每条边被赋予一个运算符“+”或“*”。所有边依次用整数从1到n编号。 现在来玩一个游戏,该游戏共有n步:

第1步,选择一条边,将其删除

随后n-1步,每一步都按以下方式操作:(1)选择一条边E以及由E连接着的2个顶点v1和v2; (2)用一个新的顶点取代边E以及由E连接着的2个顶点v1和v2,将顶点v1和v2的整数值通过边E上的运算得到的结果值赋给新顶点。

最后,所有边都被删除,只剩一个顶点,游戏结束。游戏得分就是所剩顶点上的整数值。那么这个整数值最大为多少?

输入

第一行为多边形的顶点数n(n ≤ 20),其后有n行,每行为一个整数和一个字符,整数为顶点上的正整数值,字符为该顶点到下一个顶点间连边上的运算符“+”或“*”(最后一个字符为最后一个顶点到第一个顶点间连边上的运算符)。

输出

输出仅一个整数,即游戏所计算出的最大值。

样例输入

4 4 * 5 + 5 + 3 + 样例输出 70 提示

小规模问题可不必用动态规划方法编程求解,仅用递归就可以求解。

计算中不必考虑计算结果超出整数表达围的问题,给出的数据能保证计算结果的有效性。 在给的例子中,计算过程为(3+4)*(5+5)=70。 源代码:

#include #include #include #include using namespace std; typedef long long int ll; const ll inf=000; int n; string s;

char op[110][110];

ll dp[110][110], dpmin[110][110]; ll a[110];

ll calc(ll a, ll b, char ch){

if(ch=='*'){ }

else if(ch=='+'){ } else{ }

return 0; return a+b; return a*b;

}

int main(){

int i, j, k, t; cin>>n;

for(i=1; i<=n; i++){ }

cin>>t; a[i]=t; cin>>s;

op[i][i+1]=s[0];

for(i=n+1; i<=2*n; i++){ }

// for(i=1; i<=2*n; i++){ // printf(\"%d \// }

// printf(\"\\n\");

for(i=n+1; i<2*n; i++){

}

op[i][i+1]=op[i-n][i+1-n]; a[i]=a[i-n];

// for(i=1; i<2*n; i++){

// printf(\"%c \// }

// printf(\"\\n\");

for(i=1; i<=2*n; i++){//初始化为最小值 }

for(i=1; i<=2*n; i++){ }

for(i=1; i<2*n; i++){ }

for(i=3; i<=n; i++){

for(j=1; j+i-1<=2*n; j++){

dp[i][i+1]=calc(a[i], a[i+1], op[i][i+1]); dpmin[i][i+1]=calc(a[i], a[i+1], op[i][i+1]); dp[i][i]=a[i]; dpmin[i][i]=a[i]; for(j=i; j<=2*n; j++){ }

dp[i][j]=-inf; dpmin[i][j]=inf;

for(k=j; kdp[j][i+j-1]=max(dp[j][i+j-1],

calc(dpmin[j][k],

dp[j][i+j-1]=max(dp[j][i+j-1], calc(dpmin[j][k], dp[k+1][i+j-1], dp[j][i+j-1]=max(dp[j][i+j-1], calc(dp[j][k], dpmin[k+1][i+j-1], dp[j][i+j-1]=max(dp[j][i+j-1], calc(dp[j][k], dp[k+1][i+j-1],

dpmin[k+1][i+j-1], op[k][k+1]));

}

for(k=j; kdpmin[j][i+j-1]=min(dpmin[j][i+j-1],

calc(dp[j][k],

dp[k+1][i+j-1], op[k][k+1]));

dpmin[j][i+j-1]=min(dpmin[j][i+j-1],

calc(dp[j][k],

dpmin[k+1][i+j-1], op[k][k+1]));

dpmin[j][i+j-1]=min(dpmin[j][i+j-1],

calc(dpmin[j][k],

dp[k+1][i+j-1], op[k][k+1]));

dpmin[j][i+j-1]=min(dpmin[j][i+j-1],

calc(dpmin[j][k],

dpmin[k+1][i+j-1], op[k][k+1])); }

}

ll ans=-inf-10000000; for(i=1; i<=n; i++){ }

cout<if(dp[i][i+n-1]>ans){ }

ans=dp[i][i+n-1]; }

}

16、最优合并问题

描述

给定k个排好序的序列s1, s2, s3,..., sk, 用2路合并算法将这k个序列合并成一个序列。假设所采用的2路合并算法合并2个长度分别为m和n的序列需要m+n-1次比较。试设计一个算法确定合并这个序列的最优合并顺序,使所需的总比较次数最少。

为了进行比较,还需要确定合并这个序列的最差合并顺序,使所需的总比较次数最多。

输入

由文件给出输入数据。第一行有1个正整数k,表示有k个待合并序列。接下来的1行中,有k个正整数,表示k个待合并序列的长度。

输出

将计算出的最多比较次数和最少比较次数输出到文件。

样例输入

4 5 12 11 2 样例输出

78 52 提示

使用贪心法进行算法设计并编程实现。

17、最优服务次序问题

描述

设有n个顾客同时等待一项服务。顾客i需要的服务时间为ti,1≤i≤n。应如何安排n个顾客的服务次序才能使平均等待时间达到最小?平均等待时间是n个顾客等待服务时间的总和除以n。

对于给定的n个顾客需要的服务时间,计算最优服务次序。

输入

由文件给出输入数据。第一行是正整数n,表示有n个顾客。接下来的1行中,有n个正整数,表示n个顾客需要的服务时间。

输出

将计算出的最小平均等待时间输出到文件。

样例输入 10 56 12 1 99 1000 234 33 55 99 812 样例输出 532.00 提示

使用贪心法设计算法并编程实现。 源代码:

#include #include using namespace std; int main() {

int n; int a[100]; scanf(\"%d\int sum=0; int temp=0; for(int i=0;isort(a,a+n); for(int i=0;iscanf(\"%d\

}

{ }

printf(\"%.2lf\return 0;

temp+=a[i]; sum+=temp;

Top