NOIP2006代码及简析

第一题,能量项链,比较经典的合并类动态规划,个人认为最简明的方程是f[i,j]=Max{f[i,j],f[i,k]+f[k+1,j]+a[i]*a[k+1]*a[j]},但这样写的话动归的循环没有办法实现,为了思维的简明,本人义无反顾的写下了记忆化搜索,效率没什么损失,都是0.01s出解,从这道题里也可以总结出一些什么,比如状态的分部规则性不明显时或者想出了动态方程但循环边界却十分纠结,记忆化搜索也是不错的选择,当然有些题目可以运用类似广度优先搜索的记忆化,属于正推,也有深搜的记忆化,其实它们本质上没有什么区别,都是状态的一些整合而已,动态规划题目并不难,看清实质就能行。

View Code
 1 Program Energy(Input,Output);
2 Var
3 F : Array[0..301,0..301] Of Longint;
4 A : Array[0..300] Of Longint;
5 N,Ans : Longint;
6 Procedure Init;
7 Var
8 I : Longint;
9 Begin
10 Readln(N);
11 For I:=1 To N Do
12 Begin
13 Read(A[I]);
14 A[I+N]:=A[I];
15 End;
16 End; { Init }
17 Function Max(Aa,Bb :Longint ):Longint;
18 Begin
19 If Aa>Bb Then
20 Exit(Aa);
21 Exit(Bb);
22 End; { Max }
23 Function Dfs(I,J :Longint ):Longint;
24 Var
25 K : Longint;
26 Begin
27 If F[I,J]<>-1 Then
28 Exit(F[I,J]);
29 For K:=I To J-1 Do
30 F[I,J]:=Max(F[I,J],Dfs(I,K)+Dfs(K+1,J)+A[I]*A[K+1]*A[J+1]);
31 Exit(F[I,J]);
32 End; { Dfs }
33 Procedure Main;
34 Var
35 I,J : Longint;
36 Begin
37 For I:=1 To N+N Do
38 For J:=1 To N+N Do
39 F[I,J]:=-1;
40 For I:=1 To N+N Do
41 F[I,I]:=0;
42 For I:=1 To N Do
43 Ans:=Max(Ans,Dfs(I,I+N-1));
44 End; { Main }
45 Begin
46 Assign(Input,'Energy.In');Reset(Input);
47 Assign(Output,'Energy.Out');Rewrite(Output);
48 Init;
49 Main;
50 Writeln(Ans);
51 Close(Input);
52 Close(Output);
53 End.

第二题,金明的预算方案,又是一道动态规划,可以用树形动归做,但是实现比较繁琐(如果是大牛请当我没说这句话),涉及泛化背包的一些知识(可以参考DD的背包九讲),如果是为了练习泛化背包,的确是个不错的题目,但考试的时候要把握全局,用最少的时间那最多的分数,题目中每个主件最多有两个附件,所以对于一组物品来说,只有以下几种方案:1.取主件,2.去主件和附件1,3.取主件和附件2,4.取主件附件1和附件2.所以只要在转移时把一组物品分四块转移,保留最大值即可,同样可以用滚动数组优化成一维。还有一个不错的优化,每个物品价值都是10的整数倍,所以可以把物品价值先都缩小10倍,最后答案*10输出即可。晒代码。

View Code
 1 {这里l和r数组记录两个附件,IM为重要程度,v是体积,vv标记主件}
2 Program Budget(Input,Output);
3 Var
4 F : Array[-35000..35000] Of Longint;
5 V : Array[1..61] Of Longint;
6 L,R : Array[1..61] Of Longint;
7 Im : Array[1..61] Of Longint;
8 Vv : Array[1..61] Of Boolean;
9 Maxv,N : Longint;
10 Procedure Init;
11 Var
12 I,J,X : Longint;
13 Begin
14 Fillchar(Vv,Sizeof(Vv),False);
15 Readln(Maxv,N);
16 For I:=1 To N Do
17 Begin
18 L[I]:=0;
19 R[I]:=0;
20 End;
21 V[I]:=0;
22 For I:=1 To N Do
23 Begin
24 Readln(V[I],Im[I],X);
25 If X=0 Then
26 Vv[I]:=True;
27 If L[X]=0 Then
28 L[X]:=I
29 Else
30 R[X]:=I;
31 End;
32 End; { Init }
33 Function Max(Aa,Bb :Longint ):Longint;
34 Begin
35 If Aa>=Bb Then
36 Exit(Aa);
37 Exit(Bb);
38 End; { Max }
39 Procedure Main;
40 Var
41 I,J : Longint;
42 Begin
43 For I:=1 To N Do
44 If Vv[I] Then
45 For J:=Maxv Downto 1 Do
46 Begin
47 If J-V[I]>=0 Then
48 F[J]:=Max(F[J],F[J-V[I]]+V[I]*Im[I]);
49 If J-V[I]-V[L[I]]>=0 Then
50 F[J]:=Max(F[J],F[J-V[I]-V[L[I]]]+Im[I]*V[I]+Im[L[I]]*V[L[I]]);
51 If J-V[I]-V[R[I]]>=0 Then
52 F[J]:=Max(F[J],F[J-V[I]-V[R[I]]]+Im[I]*V[I]+Im[R[I]]*V[R[I]]);
53 If J-V[I]-V[L[I]]-V[R[I]]>=0 Then
54 F[J]:=Max(F[J],F[J-V[I]-V[R[I]]-V[L[I]]]+Im[I]*V[I]+Im[L[I]]*V[L[I]]+Im[R[I]]*V[R[I]]);
55 End;
56 Writeln(F[Maxv]);
57 End; { Main }
58 Begin
59 Assign(Input,'Budget.In');Reset(Input);
60 Assign(Output,'Budget.Out');Rewrite(Output);
61 Init;
62 Main;
63 Close(Input);
64 Close(Output);
65 End.

第三题,终于不是动规题了,再一看,恶心的模拟题,不过再恶心也是模拟题,用数组记录各个工件当前完成的状态,记录时间,下一个步骤最早能开工的时间,当前机器的状态,顺便表示一下时间轴即可,注意读入时不要人工readln,第六个点有错误,数据告诉你每行8个,但有一行有九个数,而且最后一个数是下一行的第一个数,也就是说,从该行开始,数据错位了,所以用read啊!谈到这里,顺便说一下防止读入错误的常识,读入全是数字就直接read,不容易出问题,如果读入是一个字符矩阵,一定要小心,要人工readln,否则回车也会被当做一个字符读进去,然后你的字符矩阵就错了……

View Code
 1 Program Jsp(Input,Output);
2 Type Integer=Longint;
3 Var
4 P : Array[-10..20,-100..10000] Of Boolean;
5 Top : Array[-100..2000] Of Integer;
6 Start : Array[-100..2000] Of Integer;
7 Longlong : Array[-100..2000] Of Longint;
8 Time : Array[-100..500,-100..500] Of Integer;
9 Need : Array[-100..500,-100..500] Of Integer;
10 Now : Array[-100..500] Of Integer;
11 M,N,Ans : Longint;
12 Procedure Init;
13 Var
14 I,J : Longint;
15 Begin
16 Readln(M,N);
17 For I:=1 To M*N Do
18 Read(Start[I]);
19 Readln;
20 For I:=1 To N Do
21 Begin
22 For J:=1 To M Do
23 Read(Need[I,J]);
24 End;
25 For I:=1 To N Do
26 Begin
27 For J:=1 To M Do
28 Read(Time[I,J]);
29 End;
30 For I:=1 To N Do
31 Longlong[I]:=1;
32 Fillchar(Now,Sizeof(Now),0);
33 Fillchar(P,Sizeof(P),False);
34 End; { Init }
35 Procedure Main;
36 Var
37 I,J,K,L : Longint;
38 Mach,Long : Longint;
39 Flag,Flag2 : Boolean;
40 Begin
41 For I:=1 To N*M Do
42 Begin
43 Inc(Now[Start[I]]);
44 Long:=Time[Start[I],Now[Start[I]]];
45 Mach:=Need[Start[I],Now[Start[I]]];
46 Flag2:=False;
47 For J:=1 To Top[Mach]+Longlong[Start[I]] Do
48 Begin
49 Flag2:=True;
50 Flag:=True;
51 For K:=J To J+Long-1 Do
52 If (P[Mach,K])Or(J<Longlong[Start[I]]) Then
53 Flag:=False;
54 If Flag Then
55 Break;
56 End;
57 If Not Flag2 Then
58 J:=Longlong[Start[I]];
59 For K:=J To J+Long-1 Do
60 P[Mach,K]:=True;
61 If J+Long-1>Top[Mach] Then
62 Top[Mach]:=J+Long-1;
63 If J+Long>Longlong[Start[I]] Then
64 Longlong[Start[I]]:=J+Long;
65 End;
66 For I:=1 To M Do
67 If Top[I]>Ans Then
68 Ans:=Top[I];
69 End; { Main }
70 Procedure Print;
71 Begin
72 Writeln(Ans);
73 End; { Print }
74 Begin
75 Assign(Input,'Jsp.In');Reset(Input);
76 Assign(Output,'Jsp.Out');Rewrite(Output);
77 Init;
78 Main;
79 Print;
80 Close(Input);
81 Close(Output);
82 End.

第四题,又来一道相当于动规的题目,实际上准确一点是递推,题目描述很清楚,但人读了之后一头雾水,耐下心来,原来是这样……  一定要明白题意,用

f[i,j]表示2^k进制数长度为i且第一段为j(这里的第一段指的是二进制按k为基本段长从低位向高位数的最后一段),则进过两个数学计算

f[i,j]=f[i,j+1]+f[i-1,j+1],由于当前长度状态仅和上一长度有关,可以用滚动数组优化,答案位数有很多,要用到高精度(这也是我认为题比较恶心的原因之一),不过昨天刚做了矩阵取数游戏,里面的高精度过程直接粘过来了,呵呵,偷个懒吧,注意计算f[i,j]要倒着计算。

View Code
 1 Program Digital(Input,Output);
2 Type
3 Numbertype = Array[0..30] Of Int64;
4 Var
5 F : Array[0..1,0..600] Of Numbertype;
6 Ans : Numbertype;
7 N,M,Length : Longint;
8 Function Plus(X,Y :Numbertype ):Numbertype;
9 Var
10 I,Len : Longint;
11 Begin
12 Fillchar(Plus,Sizeof(Plus),0);
13 If X[0]>Y[0] Then
14 Len:=X[0]
15 Else
16 Len:=Y[0];
17 For I:=1 To Len Do
18 Begin
19 Plus[I]:=Plus[I]+X[I]+Y[I];
20 Plus[I+1]:=Plus[I] Div 100000000;
21 Plus[I]:=Plus[I] Mod 100000000;
22 End;
23 If Plus[Len+1]<>0 Then
24 Plus[0]:=Len+1
25 Else
26 Plus[0]:=Len;
27 End; { Plus }
28 Procedure Print(X: Numbertype );
29 Var
30 I : Longint;
31 Begin
32 Write(X[X[0]]);
33 For I:=X[0]-1 Downto 1 Do
34 Begin
35 Write((X[I] Div 10000000));
36 Write((X[I] Div 1000000) Mod 10);
37 Write((X[I] Div 100000) Mod 10);
38 Write((X[I] Div 10000) Mod 10);
39 Write((X[I] Div 1000) Mod 10);
40 Write((X[I] Div 100) Mod 10);
41 Write((X[I] Div 10) Mod 10);
42 Write((X[I] Mod 10));
43 End;
44 End; { Print }
45 Procedure Init;
46 Var
47 I : Longint;
48 Begin
49 Readln(M,N);
50 Length:=N Div M;
51 Ans[0]:=1; {对于Ans数组的初始化}
52 Ans[1]:=0;
53 For I:=1 To ((1<<M)-1) Do
54 Begin
55 F[0,I][0]:=1;
56 F[0,I][1]:=1;
57 End;
58 End; { Init }
59 Procedure Main;
60 Var
61 I,J : Longint;
62 Position : Integer;
63 Begin
64 For I:=1 To Length-1 Do
65 Begin
66 Position:=I Mod 2;
67 For J:=(1<<M)-1 Downto 1 Do
68 Begin
69 F[Position,J]:=Plus(F[1-Position,J+1],F[Position,J+1]);
70 Ans:=Plus(Ans,F[Position,J]);
71 End;
72 End;
73 If (N Mod M>0) Then {有多余的段}
74 Begin
75 Position:=Length Mod 2;
76 For I:=(1<<M)-1 Downto 1 Do
77 Begin
78 F[Position,I]:=Plus(F[1-Position,I+1],F[Position,I+1]);
79 If (1<<(N Mod M))-1>=I Then
80 Ans:=Plus(Ans,F[Position,I]);
81 End;
82 End;
83 End; { Main }
84 Begin
85 Assign(Input,'Digital.In');Reset(Input);
86 Assign(Output,'Digital.Out');Rewrite(Output);
87 Init;
88 Main;
89 Print(Ans);
90 Close(Input);
91 Close(Output);
92 End.
posted @ 2011-10-17 17:55  Codinginging  阅读(1247)  评论(1编辑  收藏  举报