四道简单的题目
1.又见汉诺塔
(hanoi.pas/c/cpp)
【 题目描述】
A 先生发明了一个小游戏。 游戏有 n 根柱子和很多球。 球被编号为 1、 2、 3…, 球看上
去很普通, 但它们实际上是有魔法的。 如果上下相邻的放在一起的两个球编号之和不是平方
数, 他们将以一个强大的力量相互排斥, 不能放在一起。
玩家每一次拿一颗球放在其中一根柱子上( 从上往下放), 玩家拿球按照 1 号, 2 号, 3
号……这样的次序依次下去。你的任务是帮忙编程计算在 n 根柱子上最多可以放多少个球,
注意当一根柱子上相邻的两个球编号之和不是平方数时是不能放在一起的。上图给出了四根
柱子的最佳放法。
【 输入格式】
输入一行一个整数 n ,表示柱子数量。
【 输出格式】
输出一行, 一个整数, 表示最多可以放的球的数量, 如果可以放无限多的球, 请输出“-1”。
【 输入样例 1】
4
【 输出样例 1】
11
【 输入样例 2】
25
【 输出样例 2】
337
【 数据规模】
对于 30%的数据: 1≤N≤15;
对于 60%的数据: 1≤N≤30;
对于 100%的数据: 1≤N≤50;
2.补做作业
(homework.pas/c/cpp)
【 题目描述】
B 同学刚刚从信息学奥赛复赛回来。 现在他有很多的作业要补做。 每一门课的老师都告
诉了他交作业的最后期限。 如果超过了某个老师告诉他的交作业最后期限, 老师会降低他最
后的考试成绩。 现在我们假设 B 同学补做每一门课的时间都需要一天。 现在请你编程帮 B
同学安排做作业的先后次序以使他最后考试的成绩损失最少。
【 输入格式】
第一行一个整数 N, 表示有 N 门课的作业要完成, 从 1 到 N 编号。
第二行 N 个整数 A[i], 依次表示第 i 门课完成作业的最后期限。
第三行 N 个整数 B[i], 依次表示第 i 门课没有在老师指定的最后期限内完成, 最后的考试
成绩要被减少的分数。
【 输出格式】
输出仅一行, 一个整数, 表示最后的考试中 B 同学最少需要被减少的分数总和。
【 输入样例 1】
3 3
3 3
10 5 1
【 输出样例 1】
0
【 输入样例 2】
3 1
3 1
6 2 3
【 输出样例 2】
3
【 输入样例 3】
7 1
4 6 4 2 4 3
3 2 1 7 6 5 4
【 输出样例 3】
5
【 数据规模】
对于 30%的数据: 1≤N≤300;
对于 60%的数据: 1≤N≤600;
对于 100%的数据: 1≤N≤1,000; 1≤A[i],B[i]≤100;
3.NOI 牛肉干
(noi.pas/c/cpp)
【 题目描述】
C 同学准备做点什么来纪念学习编程这段激情燃烧的岁月, 他从家里拿来了一块上等的
牛肉干, 准备在上面刻下一个长度为 N 的只由大写字母”N” “O” “I”三种字符组成的字符串
( 可以只有其中一种或两种字符) ,但 C 同学认为, 两个连续的”O”(即”OO”)看起来就像发怒
的眼睛, 十分不和谐。 请你编程计算一共有多少种满足要求的不同字符串。
【 输入格式】
一行一个整数 N,表示要刻的字符串长度。
【 输出格式】
输出仅一行, 一个整数, 表示满足要求的不同字符串数。
【 输入样例 1】
1
【 输出样例 1】
3
【 输入样例 2】
2
【 输出样例 2】
8
【 数据规模】
对于 30%的数据: 1≤N≤15;
对于 60%的数据: 1≤N≤25;
对于 100%的数据: 1≤N≤40;
4.高速乘车
(car.pas/c/cpp)
【 题目描述】
D 星有许多城市, 城市之间通过一种奇怪的高速公路连接, 每条高速公路都对行驶在上
面的汽车限制了固定的速度( 必须以这个速度行驶, 且汽车的提速和减速是瞬间完成的),
同时 D 星人对汽车的“ 舒适度” 有特殊要求, 即乘车过程中最高速度与最低速度的差越小越
舒服 , 但 D 星人对时间却没有很高的要求。 请编程找出最舒适的行车路线。 (高速公路是双
向的)。
【 输入格式】
第一行有 2 个正整数 n 和 m ,表示有 n 个城市和 m 条高速公路, 城市从 1 到 n 编号。
接下来的 m 行, 每行三个正整数 S,E,K, 表示从 S 到 E 有一条限速为 K 的高速公路。
接下来一行是一个正整数 Q,表示需要寻找的行车线路条数。
接下来 Q 行每行有 2 个正整数 A,B, 分别表示寻路的起点和终点。
【 输出格式】
输出 Q 行, 每行一个整数, 表示相应舒适度最好的线路的最高速与最低速之差。 如果从起点
不能到达终点, 那么输出“-1”( 不包括双引号)。
【 输入样例】
4 4
1 2 2
2 3 4
1 4 1
3 4 2
2 1
3
1 2
【 输出样例】
1 0
【 数据规模】
对于 30%的数据: 2≤n≤50; 1≤m≤100; 1≤K≤100;
对于 50%的数据: 2≤n≤100; 1≤m≤500; 1≤K≤100,000;
对于 100%的数据: 2≤n≤200; 1≤m≤1,000; 1≤K≤1,000,000; 1≤S,E≤n,S≠E;
1≤Q≤10; 1≤A,B≤n,A≠B;
第一题:
此题一看,感觉无从下手,但是仔细推敲,发现有一个巧妙的规律,
f[1]=1;f[2]=3;f[3]=7;f[4]=11;f[5]=17;f[6]=23;
看出来规律了吗?
#include<cstdio>
#include<cstdlib>
using namespace std;
int i,j,k,n,m,ans,tot;
int f[50];
int main()
{
scanf("%d",&n);
f[1]=1;tot=2;
for(int i=2;i<=n;i++){
f[i]=f[i-1]+tot;
if(i%2==0) tot+=2;
}
printf("%d",f[n]);
return 0;
}
当然还有O1的写法
#include <cstdio>
using namespace std;
int n;
int main(){
scanf("%d",&n);
if(!(n&1))printf("%d",n+1+(n*n-4)/2);
else printf("%d",n+(n*n-1)/2);
return 0;
}
2.此题也介绍两种打法。
(I).我们可以用简单的贪心,按照每门科目扣得分从大到小排序,易知限时日期为x的任务在第x天完成最优(不会影响其他的不同天的任务)。但是一天可能有好多任务,如果限时的日期x已经被其他扣得分更多的任务使用了,那么当前任务就往前推,直到有空闲的时间。如果没有,就将这些分扣除。利用贪心的原理,就可以保证扣得分尽量少。
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
struct A
{
int dead,score;
}E[1011];
int hash[1011];
int cmp(const void *a,const void *b)
{
A *c,*d;
c=(A *)a;
d=(A *)b;
if(c->score!=d->score) return d->score-c->score;
else return c->dead-d->dead;
}
int main()
{
int n;
int i,l;
int ans;
scanf("%d",&n);
E[0].dead=-1;
E[0].score=11111111;
for(i=1;i<=n;i++) scanf("%d",&E[i].dead);
for(i=1;i<=n;i++) scanf("%d",&E[i].score);
qsort(E,n+1,sizeof(E[0]),cmp);
ans=0;
memset(hash,0,sizeof(hash));
for(i=1;i<=n;i++)
{
for(l=E[i].dead;l>0;l--) if(hash[l]==0) {hash[l]=1;break;}
if(l<=0) ans+=E[i].score;
}
printf("%d
",ans);
return 0;
}
此种解法是粘贴大神的标程。下面是我用的方法:
(II).第二种方法是用堆,按照期限日期从小到大排序,如果日期一样,就按任务扣分从大至小排,然后按时间从小到大向后扫去,确保每天都拿扣分最多的任务,并且将此任务加入小根堆中。之后,将本日的其他任务与小根堆的堆顶比较,如果此任务扣得分比小根堆顶多,就将小根堆顶删除,答案加上小根堆顶。将此任务放入小根堆中,即可维护从大到小。(相当于将此人无放到小根堆堆顶的任务那天做,小根堆堆顶的任务不做,由于是小根堆,可以维护从小到大)。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
int i,j,k,n,m,tot,ans,top,time,to;
struct node{
int t,w;
}f[1005];
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int cmp(node a,node b){
if(a.t<b.t) return 1;
if(a.t==b.t&&a.w>b.w) return 1;
return 0;
}
priority_queue <int> a;
int maxn(int a,int b){return a>b?a:b;}
int main()
{
n=read();
for(int i=1;i<=n;i++){
f[i].t=read();
time=maxn(time,f[i].t);
}
for(int i=1;i<=n;i++) f[i].w=read();
sort(f+1,f+1+n,cmp);k=1;top=0;to=1;
while(k<=time){
a.push(f[to].w*(-1));
if(k==f[to].t) for(int j=to+1;j<=n;j++){
if(f[j].t!=f[to].t){
to=j-1;break;
}
if(f[j].w>(a.top()*(-1))){
ans+=(-1)*a.top();
a.pop();
a.push(f[j].w*(-1));
}
else ans+=f[j].w;
}
k++;to++;
}
printf("%d",ans);
return 0;
}
//大根堆读入输出是乘上-1就可以当小根堆用
当然pascal的同学也可以用pascal打堆,操作相对复杂,但炉火纯青的同学可以随意。@cjj.
3.
此题我们可以从头开始,往下写,即可发现规律。(如图)。
f[i][N]=f[i-1][N]+f[i-1][O]+f[i-1][I]
f[i][O]=f[i-1][N]+f[i-1][I]
f[i][I]=f[i-1][N]+f[i-1][O]+f[i-1][I]
因为新的I,N可以从上一个情况的N,O,I全部生成,而O只能从N,I生成。
#include<cstdio>
#include<cstdlib>
using namespace std;
long long i,j,k,n,m,tot;
long long f[45][4],ans[45];
int main()
{
scanf("%d",&n);
f[1][1]=f[1][2]=f[1][3]=1;ans[1]=3;
for(int i=2;i<=n;i++){
f[i][1]=f[i-1][1]+f[i-1][2]+f[i-1][3];
f[i][2]=f[i-1][1]+f[i-1][3];
f[i][3]=f[i-1][1]+f[i-1][2]+f[i-1][3];
ans[i]=f[i][1]+f[i][2]+f[i][3];
}
printf("%lld",ans[n]);
return 0;
}
4.此题一看像是最短路,但是最大与最小的差值却不是特别好求,
再仔细看一下题目,无向边,最大与最小,是不是有点想生成一棵树?我们只要将边从小到大将边排序,然后生成一棵树,只要将起点与终点联合在一个集合里,就完成了一条路,再将此路上最大的边(最后一条边)减去最小的边,即为答案。然后每次枚举取一个min值,及是答案的值。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int i,j,k,n,m,tot,ans,q,st,en,s1,s2,pp,re,re1;
int fa[205];
struct node{
int a,b,len;
}a[1005];
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int find(int x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void unionn(int x,int y){
x=find(x);y=find(y);
if(x>y) fa[x]=y;
else fa[y]=x;
}
int cmp(node a,node b){
if(a.len<b.len) return 1;
else return 0;
}
int minn(int a,int b){return a<b?a:b;}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++){
a[i].a=read();a[i].b=read();a[i].len=read();
}
q=read(); sort(a+1,a+1+m,cmp);
for(int i=1;i<=q;i++){
for(int tt=1;tt<=n;tt++) fa[tt]=tt;
ans=200000000;re=0;
st=read();en=read();
for(int j=1;j<=m;j++){
for(int tt=1;tt<=n;tt++) fa[tt]=tt;
s1=a[j].len;
unionn(a[j].a,a[j].b);
for(int pp=j+1;pp<=m+1;pp++){
re1=0;
if(find(st)==find(en)){
s2=a[pp-1].len;re=1;re1=1;break;
}
unionn(a[pp].a,a[pp].b);
}
if(re1==1) ans=minn(ans,s2-s1);
}
if(re==1)printf("%d
",ans);
else printf("-1
");
}
return 0;
}