一:
最优分解方案
(best.pas/c/cpp)
[问题描述]
经过第一轮的游戏,不少同学将会获得圣诞特别礼物,但这时细心的数学课代表发现了一个问题:留下来的人太多而使礼物数量可能不够,为此,加试了一道数学题:将一个正整数n分解成若干个互不相等的正整数的和,使得这些数的乘积最大,当主持人报出一个n后,请你立即将这个最大值报出来,现请你帮你的好友编一个程序来解决这个问题。
[输入文件]
输入文件best.in中只有1个数n(其中1<=n<=1000)。
[输出文件]
输出文件best.out中也是一个数,是乘积的最大值。
[输入样例]
7
[输出样例]
12
首先需要用贪心找出乘积最大的正整数;
举例可知:5=2+3
6+2+4
7+3+4
8=3+5
9=2+3+4
取x个最小值为2,依次大1,总和小于等于n的数,剩余的数为k
从第x个数依次向前加1,直到k被减为0;
此时的x个数乘积最大;
再用高精乘单精,得到最后答案。
code:
var n:longint;
init:array[0..1000]of longint;
i,j,k:longint;
f:array[1..1000,0..1000]of integer;
g,h:array[0..1000]of longint;
len:longint;
procedure divide(x:longint);
var i,j,k:longint;
begin i:=2; k:=x;
while k>i do
begin inc(init[0]);
init[init[0]]:=i;
k:=k-i;
inc(i);
end;
i:=init[0];
while k>0 do
begin if i<=0
then begin inc(init[0]);
inc(init[init[0]]);
dec(k);
end
else begin inc(init[i]);
dec(k);
dec(i);
end;
end;
end;
begin assign(input,'best.in');
assign(output,'best.out');
reset(input);
rewrite(output);
readln(n);
divide(n);
fillchar(f,sizeof(f),0);
fillchar(g,sizeof(g),0);
g[0]:=1; g[1]:=1;
for i:=1 to init[0] do
begin len:=g[0]+10;
for j:=1 to g[0] do
g[j]:=g[j]*init[i];
for j:=1 to len do
begin g[j+1]:=g[j+1]+g[j] div 10;
g[j]:=g[j] mod 10;
end;
while g[len]=0 do
dec(len);
g[0]:=len;
end;
for i:=len downto 1 do
write(g[i]);
close(input);
close(output);
end.
____________________________________________________________________________________________________
2,
圣诞树
(tree.pas/c/cpp)
[问题描述]
圣诞特别礼物挂在一棵圣诞树上,这棵树有n层,每层有一件礼物,每件礼物都有一个价值,有的礼物还有一些连结线,与下层的礼物相连,领取礼物的规则如下:任选一件礼物,它的下面如果有连结线,则可以继续取它连结的礼物,以此类推,直至取到没有连结线的礼物才结束,你如果是第一个去取,怎样取才能获得最大的价值呢?请你编一程序解决这一问题。
[输入文件]
输入文件tree.in的第一行只有一个数据n(n<=100),表示有n层礼物,以下有n行数据,分别表示第1-n层礼物的状态,每行至少由一个数据构成,且第一个数据表示该礼物的价值,后面的数据表示它与哪些层的礼物相连,如果每行只有一个数据则说明这层礼物没有与下层礼物相连,每个数的大小均不超过10000。
[输出文件]
输出文件tree.out也只有一个数,表示获得的取大价值。
[输入样例]
3
12 2 3
20
30
[输出样例]
42
如果搜索,肯定会超时,考虑其他算法
从底层开始处理,
如果下层无连接线,则f[i]=init[i]
~~~~~~~有~~~~~,则f[i]=init[i]+min{f[j]} {i,j中有连接线,j在i的下层}
code:
var n,num:longint;
ii,i,j,k,l:longint;
son:array[1..1000]of longint;
init:array[1..1000]of longint;
ans:array[1..1000]of longint;
s:string;
x,max:longint;
xx:longint;
map:array[1..100,1..100]of boolean;
begin assign(input,'tree.in');
assign(output,'tree.out');
reset(input);
rewrite(output);
readln(n);
fillchar(map,sizeof(map),false);
for ii:=1 to n do
begin readln(s);
s:=s+' '; i:=1;
while s[i]<>' ' do inc(i);
val(copy(s,1,i-1),init[ii],l);
x:=i+1;
num:=0;
j:=1; k:=1; l:=i+1;
for i:=x to length(s) do
if s[i]=' '
then begin k:=i-1;
j:=l;
l:=i+1;
val(copy(s,j,k-j+1),x,xx);
map[ii,x]:=true;
inc(num);
end;
son[ii]:=num;
end;
for i:=n downto 1 do
if son[i]=0
then ans[i]:=init[i]
else begin max:=0;
for j:=i+1 to n do
if map[i,j] and (ans[j]>max)
then max:=ans[j];
ans[i]:=max+init[i];
end;
max:=0;
for i:=1 to n do
if max<ans[i]
then max:=ans[i];
writeln(max);
close(input);
close(output);
end.
——————————————————————————————————————————————————————————————————————————————————————————————————————————
3,
暴力摩托
(car.pas/c/cpp)
[问题描述]
晚会上大家在玩一款“暴力摩托”的游戏,它拥有非常逼真的画面和音响效果,如疾驰而过的汽车呼啸声,摩托车的引擎声和转弯时轮胎与地面摩擦而产生的声音。而且它在游戏中加入了对抗成份,比赛中你可以使用拳、脚去干扰对方,使其落后于你,是不是很卑鄙啊? 游戏中千万不能手下留情,因为对手会主动攻击你。如果遇到开摩托车的警察,虽然也可以对他踢上一脚,但可得小心点呀,万一被他们捉住了,那就 GAME OVER 啦!
当然了,车子总是要加油的咯,已知赛道长S公里(S≤10000整数,且为10的倍数),赛车的油耗Q=1,即1公里路耗1个单位的油。Q不变,赛车的油箱为无穷大,同时在沿途的任何地方都可以加油。 约定,每次加油的数量为整数,且为10的倍数,赛车的速度与赛车加油后的总油量有关。其关系如下表列出:
加油量 | 车速(公里/小时) |
≤10 | 100 |
(10,20 ] | 90 |
(20,30 ] | 80 |
(30,40 ] | 75 |
(40,+∞) | 70 |
同时,汽车每加油一次需要耗费T分钟(T<=100不论加油多少,开始时的加油不计时间)
当S,T给出之后,选择一个最优的加油方案。使汽车以最少时间跑完全程。
例如:当S=40,T=6(分钟),加油的方案有许多种,列出一些:
1)起点加油40,用时40/75≈0.53小时
2)起点加油20,中途加20,用时20/90+20/90+6/60(化为小时)≈ 0.54 小时
[输入文件]
一行,为两个整数S、T。
[输出文件]
输出一行,为最少用时(保留二位小数)
[输入样例]
40 6
[输出样例]
0.53
动态规划:
f[i]+t/60=min{f[i-10]+i/100+t/60
f[i-20]+i/90+t/60
f[i-30]+i/80+t/60
f[i-40]+i/75+t/60
i/70+t/60}
code:
var f:array[0..1000]of real;
i,j,k:longint;
s,t:longint;
min:real;
begin assign(input,'car.in');
assign(output,'car.out');
reset(input);
rewrite(output);
readln(s,t);
f[0]:=0;
for i:=1 to s div 10 do
begin if i=1
then f[i]:=0.1+t/60;
if i=2
then begin min:=maxlongint;
if f[i-1]+0.1+t/60<min
then min:=f[i-1]+0.1+t/60;
if 20/90+t/60<min
then min:=2/9+t/60;
f[i]:=min;
end;
if i=3
then begin min:=maxlongint;
if f[i-1]+0.1+t/60<min
then min:=f[i-1]+0.1+t/60;
if f[i-2]+2/9+t/60<min
then min:=f[i-2]+2/9+t/60;
if 30/80+t/60<min
then min:=3/8+t/60;
f[i]:=min;
end;
if i=4
then begin min:=maxlongint;
if f[i-1]+0.1+t/60<min
then min:=f[i-1]+0.1+t/60;
if f[i-2]+2/9+t/60<min
then min:=f[i-2]+2/9+t/60;
if f[i-3]+30/80+t/60<min
then min:=f[i-3]+3/8+t/60;
if 40/75+t/60<min
then min:=40/75+t/60;
f[i]:=min;
end;
if i>4
then begin min:=maxlongint;
if f[i-1]+0.1+t/60<min
then min:=f[i-1]+0.1+t/60;
if f[i-2]+2/9+t/60<min
then min:=f[i-2]+2/9+t/60;
if f[i-3]+30/80+t/60<min
then min:=3/8+t/60;
if f[i-4]+40/75+t/60<min
then min:=f[i-4]+40/75+t/60;
if i/70+t/60<min
then min:=i/70+t/60;
f[i]:=min;
end;
end;
writeln(f[s div 10]-t/60:0:2);
close(input);
close(output);
end.