百练C++测试:六题简析
[malicTOC]
A:找和最接近但不超过K的两个元素
序列a中有N个整数,从中找出两个数,使两数之和最接近K但不超过K。\( (1<N<1000,0 \le K \le2000,0 \le a_i \le 1000) \), 输出数据为最接近但不超过K的 两数之和。
此题数据量很小,遍历数组的所有两数之和即可。时间复杂度主要在排序上,为\( O(N^2 \log(N)) \)
#include <cstdio> #include <algorithm> using std::sort; using std::binary_search; int main(void) { int i,N,K; int *a,*p; scanf("%d",&N); a=new int [N]; p=new int [N*(N-1)]; scanf("%d",&K); for(i=0;i<N;i++) { scanf("%d",a+i); } int idx=0; for(i=0;i<N;i++) { for(int j=i+1;j<N;j++) { p[idx++]=a[i]+a[j]; } } sort(p,p+idx); for(i=0;i<K;i++) { if(binary_search(p,p+idx,K-i)) { printf("%d\n",K-i); break; } } return 0; }
B:附近编号最大的城市
有N座城市编号为1到N,给出N座城市之间的直接距离,在所有与城市1到距离不超过K的城市中,输出编号最大的城市
单源最短路,可以用Dijkstra算法也可以用Folyd算法,本题不需要保存路径所以用Folyd简便一点。求出城市1到所有城市的最短距离,然后从城市编号N倒序遍历,若有城市的最短距离小于K则输出这个城市编号并结束程序。
#include <cstdio> #include <algorithm> using std::min; #define MAXN 12 int N,K; int edge[MAXN][MAXN]; int main(void) { scanf("%d",&N); scanf("%d",&K); for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { scanf("%d",&(edge[i][j])); } } for(int t =0;t<N;t++) { for(int i=1;i<N;i++) { edge[0][i] = min(edge[0][i],edge[0][t]+edge[t][i]); } } int i; for(i=N-1;i>=0;i--) { if(edge[0][i]<=K) { break; } } printf("%d\n",i+1); return 0; }
C:硬币问题
有N种硬币,每种硬币的数量不限。已知各硬币的重量w和面值p,在总重量不超过C的情况下,计算最大可能的金额。\( (N\le 100, C \le 1000,0<w, p \le100) \)
此题用贪心算法:计算已知硬币的”金额/重量”之比。把金额重量比最高者尽量多地利用,若剩下的重量不足以再取得,就从不大于剩余重量的硬币中尽量多的利用金额重量比最高的,直至没有硬币可用。
#include <cstdio> #include <algorithm> using std::sort; struct cNode { int w,p; double r; bool operator<(const cNode o) { return r<o.r; } }; int main(void) { int N,R,i; int *a; cNode *coins; scanf("%d",&N); scanf("%d",&R); coins = new cNode [N]; a = new int [N]; for(int i=0;i<N;i++) { scanf("%d",a+i); } for(int i=0;i<N;i++) { coins[i].w = a[i]; scanf("%d",&(coins[i].p)); coins[i].r = coins[i].w * 1.0/coins[i].p; } sort(coins,coins+N); int sumPrice = 0; for(i=0;i<N;i++) { sumPrice += (R/coins[i].w) * coins[i].p; R = R % coins[i].w; } printf("%d\n",sumPrice); return 0; }
D:制作蛋糕
制作一个香蕉蛋糕需要2个单位的香蕉,250个单位的面粉,75个单位的糖,100个单位的黄油。
制作一个巧克力蛋糕需要75个单位的可可粉,200个单位的面粉,150个单位的糖,150个单位的黄油。
一个香蕉蛋糕可以卖出400元,
一个巧克力蛋糕可以卖出450元。
为了避免蛋糕变质,每种蛋糕至多只能制作100个。 已知每种原料的数量, 计算利用这些原料最多可以卖多少钱。
此题流程复杂但算法容易,整理好逻辑再写程序。一种方案是:先把所有原料用来做香蕉蛋糕,看看最多能做多少,再看剩下的原料能做多少巧克力蛋糕。由于巧克力蛋糕比香蕉蛋糕卖得贵,就反复试验:少做一个香蕉蛋糕余下来的原料能否做成巧克力蛋糕,若能就把香蕉蛋糕换成巧克力蛋糕,若不能则就按照这个香蕉蛋糕和巧克力蛋糕的数量进行售卖。稍复杂的情况是若原料能做超过100个香蕉蛋糕,则尝试做巧克力蛋糕之后要再检查能否做成香蕉蛋糕,不然可能原料是够做100个香蕉蛋糕的实际却因为换成了巧克力蛋糕而少做了。
#include <cstdio> #include <algorithm> using std::min; int banana,flour,sugar,butter,choc; int howManyBananaCakeToMake() { int v = min(banana/2,flour/250); v=min(v,sugar/75); v=min(v,butter/100); return v; } int howManyChocCakeToMake() { int v = min(choc/75,flour/250); v=min(v,sugar/150); v=min(v,butter/150); return v; } void makeBananaCake(int c) { banana -= 2*c; flour -= 250 *c; sugar -=75*c; butter -=100*c; } void makeChockCake(int c) { choc -= 75*c; flour -= 250*c; sugar -= 150*c; butter -= 150*c; } int main(void) { scanf("%d",&flour); scanf("%d",&banana); scanf("%d",&sugar); scanf("%d",&butter); scanf("%d",&choc); int num_bananas,num_choc; num_bananas = howManyBananaCakeToMake(); if(num_bananas>100) { makeBananaCake(100); num_bananas=100; num_choc = howManyChocCakeToMake(); if(num_choc>=100) { printf("%d\n100\n100\n",100*400+100*450); return 0; } while(1) { makeBananaCake(-1); if(howManyBananaCakeToMake()==0) { break; } num_bananas-=1; makeChockCake(1); num_choc+=1; if(howManyBananaCakeToMake()==1) { makeBananaCake(1); num_bananas+=1; } } printf("%d\n",num_bananas*400+num_choc*450); printf("%d\n%d\n",num_bananas,num_choc); } else { makeBananaCake(num_bananas); num_choc = howManyChocCakeToMake(); makeChockCake(num_choc); while(1) { makeBananaCake(-1); if(howManyChocCakeToMake()==0) { break; } makeChockCake(1); num_bananas-=1; num_choc+=1; } printf("%d\n",num_bananas*400+num_choc*450); printf("%d\n%d\n",num_bananas,num_choc); } return 0; }
E:最短路
N座城市编号从1到N,已知所有城市间的直线距离,求1号城市到N号城市的最短路程。输出途经的城市编号。
单源最短路径并且要输出路径,用Dijkstra算法。
#include <cstdio> #define MAXN 12 int N; int dist[MAXN],path[MAXN],S[MAXN]; int G[MAXN][MAXN]; void dijkstra(int v0) { int i,j,k; for(i=0;i<N;i++) { dist[i]=G[v0][i]; S[i]=0; if(i!=v0) { path[i] = v0; } else { path[i] = -1; } } S[v0] = 1; dist[v0]=0; for(i=0;i<N-1;i++) { int minVal = 0x7FFFFFF,u=v0; for(j=0;j<N;j++) { if(!S[j] && dist[j]<minVal) { u=j; minVal = dist[j]; } } S[u] = 1; for(k=0;k<N;k++) { if(!S[k] && dist[u]+G[u][k] < dist[k]) { dist[k] = dist[u] + G[u][k]; path[k] = u; } } } } int main(void) { int i,j; scanf("%d",&N); for(i=0;i<N;i++) { for(j=0;j<N;j++) { scanf("%d",&G[i][j]); } } dijkstra(0); int shortest[MAXN]; int k = 0; shortest[k] = N-1; while(path[shortest[k]]!=0) { k++; shortest[k] = path [shortest[k-1] ]; } k++; shortest[k]=0; printf("%d\n",dist[N-1]); for(j=k;j>0;j--) { printf("%d ",1+shortest[j]); } printf("%d\n",1+shortest[0]); return 0; }
F:木材切割
一根长度为N的木材切成M段,每段都是整数。长度为L的一段木材售价为P[L]。给出所有的P[],试计算一种切割方案,使这一根木头的售价最高。
搜索
#include <cstdio> #include <algorithm> using std::max; #define MAXN 102 int comb[MAXN]; int ppc[MAXN]; int profits=0; int N,M; void genComb(int n,int m) { if(n<1) return ; if(m==2) { for(int i=1;i<n;i++) { comb[0]=i; comb[1]=n-i; } int S=0; for(int k=0;k<M;k++) { S += ppc[comb[k]]; } profits = max(profits,S); return ; } for(int i = 1;i<=n-m;i++) { comb[m-1] = i; genComb(n-i,m-1); } } int main(void) { int n,m; scanf("%d",&N); scanf("%d",&M); for(int k=1;k<=N;k++) { scanf("%d",ppc+k); } n=N; m=M; profits = 0; genComb(n,m); printf("%d\n",profits); return 0; }