usaco第二章我的所有题解和程序(一)
http://hi.baidu.com/mfs666/blog/item/533d243f182902ea54e7230e.html
usaco第二章的题解和程序一直攒着没发,这几天全做完了,一起发了吧,为了不超过长度限制,依然一帖一章。时间长了,有的都记不清楚了。
usaco2.1
2.1.1 The Castle (castle)
这个题就是floodfill的典型应用,用dfs灌水,有水则退出,开一个标志记录是否是水源而不是被灌到的,如果是水源就开新的记录,否则就添加到正在使用的记录中,并使房间面积加一,加上有水的标志,这样对每个房间单位灌水后,就统计出了房间的个数和每个房间的面积,这样求出最大面积。然后枚举每面可以推倒的墙,由于有规定,所以我们只枚举墙南面和西面的房间,求出最大的。求的过程中注意:1.由于对有多个解释的规定,我们从左下向右上枚举,并且同一个房间中的墙先西后南,这样可以自动忽略不优先选择的相同解,而不用都记下来再选择(不要犯傻,我一开始就想犯来着,能按顺序扩展就不要都扩展出来再判断)。2.注意一个细节,一面墙两边可能是同一个房间。。。(很重要,我一开始就忘了,太笨了。。。)
这个题很WS,有很多细节需要注意
code:
{
ID: mfs.dev2
PROG: castle
LANG: PASCAL
}
program castle;
type v=array[1..8] of integer;
k=array[1..3] of integer;
var
n,m,c,rn,i,j,t,max,min,p,max1:longint;
e:array[-1..51,-1..51] of v;
ro:array[0..2508] of longint;
rw:k;
procedure fp(a,b,c:integer);
procedure ww;
begin
e[a,b][1]:=1;
end;
procedure nn;
begin
e[a,b][2]:=1;
end;
procedure ee;
begin
e[a,b][3]:=1;
end;
procedure ss;
begin
e[a,b][4]:=1;
end;
begin
case c of
1:ww;
2:nn;
4:ee;
8:ss;
3:begin ww;nn; end;
5:begin ee;ww; end;
9:begin ww;ss; end;
6:begin nn;ee; end;
10:begin nn;ss; end;
12:begin ee;ss; end;
7:begin ww;nn;ee; end;
11:begin ww;nn;ss; end;
13:begin ww;ee;ss; end;
14:begin nn;ee;ss; end;
15:begin nn;ee;ss;ww; end;
end;
end;
procedure ff(a,b,c,d:longint);
begin
if e[a,b][8]=1 then exit;
e[a,b][8]:=1;
if (c=a) and (d=b) then begin
inc(rn);
end;
inc(e[c,d][7]);
inc(ro[rn]);
e[a,b][5]:=c;
e[a,b][6]:=d;
if e[a,b][1]=0 then
ff(a-1,b,c,d);
if e[a,b][2]=0 then
ff(a,b-1,c,d);
if e[a,b][3]=0 then
ff(a+1,b,c,d);
if e[a,b][4]=0 then
ff(a,b+1,c,d);
end;
begin
assign(input,'castle.in');
assign(output,'castle.out');
reset(input);
rewrite(output);
readln(m,n);
for i:=1 to n do begin
for j:=1 to m do begin
read(t);
fp(j,i,t);
end;
readln;
end;
max:=0;
for i:=1 to m do
for j:=1 to n do
ff(i,j,i,j);
for i:=1 to m do
for j:=n downto 1 do begin
if (e[i,j][2]=1) and ((e[i,j-1][5]<>e[i,j][5]) or (e[i,j-1][6]<>e[i,j][6])) then begin
if j-1>=1 then begin
p:=e[e[i,j][5],e[i,j][6]][7]+e[e[i,j-1][5],e[i,j-1][6]][7];
if p>max then
begin
max:=p;
rw[1]:=i;
rw[2]:=j;
rw[3]:=2;
end;
end;
end;
if (e[i,j][3]=1) and ((e[i+1,j][5]<>e[i,j][5]) or (e[i+1,j][6]<>e[i,j][6])) then begin
if i+1<=m then begin
p:=e[e[i,j][5],e[i,j][6]][7]+e[e[i+1,j][5],e[i+1,j][6]][7];
if p>max then
begin
max:=p;
rw[1]:=i;
rw[2]:=j;
rw[3]:=3;
end;
end;
end;
end;
for i:=1 to rn do
if ro[i]>max1 then
max1:=ro[i];
writeln(rn);
writeln(max1);
writeln(max);
write(rw[2],' ');
write(rw[1],' ');
if rw[3]=3 then
writeln('E')
else
writeln('N');
close(output);
end.
usaco 2.1.2 Ordered Fractions (frac1)
这个题是原来学排序时候的例题。。。仍然按那个方案做,神奇的数学方法(法雷数列树)没有使用,因为貌似只有这一个作用,就不管了。枚举分母分子,求最大公约数(辗转相除或中国相减法),若是1就是即约,然后求出各分数值,快排,精度不会有问题。0/0和1/1事先输出。
code:
{
ID: mfs.dev2
PROG: frac1
LANG: PASCAL
}
program frac1;
Var
a,b,d:array[0..160*160] of longint;
r:array[0..160*160] of real;
i,j,n,c,q:longint;
Procedure qs(s,t:longint);
var
i,j,t2,t3:longint;
x,t1:real;
begin
i:=s; j:=t; x:=r[(i+j) div 2];
repeat
while (r[i]<x) do inc(i);
while (r[j]>x) do dec(j);
if (i<=j) then begin
t1:=r[i]; r[i]:=r[j]; r[j]:=t1;
t2:=a[i]; a[i]:=a[j]; a[j]:=t2;
t3:=b[i]; b[i]:=b[j]; b[j]:=t3;
inc(i); dec(j);
end;
until i>j;
if (s<j) then qs(s,j);
if (i<t) then qs(i,t);
end;
function GCD(x,y: integer): integer;
Var n:integer;
begin
While x mod y<>0 do
begin
n:=x; x:=y; y:=n mod y
end;
GCD:=y;
end;
begin
assign(input,'frac1.in');
assign(output,'frac1.out');
reset(input);
rewrite(output);
readln(n);
Writeln('0/1');
c:=0;
For i:=2 to n do
For j:=1 to i-1 do
if gcd(j,i)=1 then
begin
inc(c);
a[c]:=j;b[c]:=i;
end;
For i:=1 to c do
begin
r[i]:=a[i]/b[i];
end;
qs(0,c-1);
For i:=1 to c do
begin
{q:=1;
While d[i]<>q do
inc(q);}
writeln(a[i],'/',b[i]);
end;
writeln('1/1');
close(input);
close(output);
end.
usaco 2.1.3 Sorting A Three-Valued Sequence (sort3)
这个其实算模拟,不过貌似有点贪心思想。输入后统计1,2,3的个数,这样的话总的序列的前n1个必须是1,后面n2个必须是2,再后面n3个必须是3,这样的相应的位置若不是,就必须要至少一次交换,交换有两种情况,把当前这个数换到它应该待的部分里面去,这样那个位置就不需要再交换了,或者换到同样不相等的位置,那么目标位置还需要一次交换,为了是交换次数最少,必须尽量按第一种情况交换,模拟,记录每一段不合要求的位的个数,模拟交换,统计次数,处理完1和2两段就可以输出了.代码里面有一段是没想好的废品,写了但是好像后来没用到。。。
code
{
ID: mfs.dev2
PROG: sort3
LANG: PASCAL
}
program sort3;
var
n,c1,c2,c3,r,i,l1,l2,tl:integer;
m:array[0..1001] of integer;
c:array[2..3,1..3] of integer;
d:array[2..3,1..3,1..1000] of integer;
procedure ch(Var a,b:integer);
var t:integer;
begin
t:=a;
a:=b;
b:=t;
end;
begin
assign(input,'sort3.in');
assign(output,'sort3.out');
reset(input);rewrite(output);
readln(n);
for i:=1 to n do begin
readln(m[i]);
case m[i] of
1:inc(c1);
2:inc(c2);
3:inc(c3);
end;
end;
l1:=c1;l2:=c1+c2;
for i:=l1+1 to l2 do begin
if m[i]=1 then begin inc(c[2,1]); d[2,1,c[2,1]]:=i; end;
if m[i]=3 then begin inc(c[2,3]); d[2,3,c[2,3]]:=i; end;
end;
for i:=l2+1 to n do begin
if m[i]=1 then begin inc(c[3,1]); d[3,1,c[3,1]]:=i; end;
if m[i]=2 then begin inc(c[3,2]); d[3,2,c[3,2]]:=i; end;
end;
for i:=1 to l1 do begin
if m[i]=1 then continue;
tl:=m[i];
if c[m[i],1]>0 then begin
ch(m[d[m[i],1,c[m[i],1]]],m[i]);
inc(r);
dec(c[tl,1]);
end else begin
ch(m[d[5-m[i],1,c[5-m[i],1]]],m[i]);
inc(r);
dec(c[5-tl,1]);
{inc(c[5-m[i],m[i]]);
d[5-m[i],m[i],c[5-m[i],m[i]]]:=d[5-m[i],1,c[5-m[i],1]+1];}
end;
end;
for i:=l1+1 to l2 do begin
if m[i]=2 then continue;
inc(r);
end;
writeln(r);
close(output);
end.
usaco2.1.4 Healthy Holsteins (holstein)
数据量很小,直接深搜吧,加一个类似最优化剪纸的东西。深搜类型是按顺序对每个位置进行选择型的(类似背包)。
code:
{
ID: mfs.dev2
PROG: holstein
LANG: PASCAL
}
program holstein;
type
v=array[0..26] of integer;
var
n,g,i,r,min,j:integer;
vv,q:v;
gg:array[0..16] of v;
ga,gf:array[1..16] of boolean;
function che(kk:v):boolean;
var
i:integer;
begin
for i:=1 to n do
if kk[i]<vv[i] then begin
che:=false;
exit;
end;
che:=true;
end;
procedure dfs(ka:v;k,c:integer);
var
i:integer;
te:v;
begin
if k>g+1 then exit;
if c>=min then exit;
if che(ka) then begin
min:=c;
gf:=ga;
exit;
end;
te:=ka;
for i:=1 to n do
inc(te[i],gg[k][i]);
ga[k]:=true;
dfs(te,k+1,c+1);
ga[k]:=false;
dfs(ka,k+1,c);
end;
begin
assign(input,'holstein.in');
assign(output,'holstein.out');
reset(input);rewrite(output);
readln(n);
for i:=1 to n do
read(vv[i]);
readln;
readln(g);
for i:=1 to g do begin
for j:=1 to n do
read(gg[i][j]);
readln;
end;
fillchar(ga,sizeof(ga),0);
fillchar(gf,sizeof(gf),0);
for i:=1 to n do
q[i]:=0;
min:=20835;
dfs(q,1,0);
write(min,' ');
j:=0;
for i:=1 to g do
if gf[i] then begin
inc(j);
q[j]:=i;
end;
for i:=1 to j-1 do
write(q[i],' ');
writeln(q[j]);
close(output);
end.
2.1.4 Hamming Codes (hamming)
进制转换和枚举搜索,时间没问题。题不是很好,说的也不是很明白,看题解了。这个题当时好像有点疑问,但是现在记不清楚了。
code:
{
ID: mfs.dev2
PROG: hamming
LANG: PASCAL
}
program hamming;
Const
p='0123456789ABCDEFGHIJ';
var
n,w,d,r,f,fl,i:integer;
m:array[0..64] of integer;
t,ta:string;
procedure cha(nu,k:longint;var s:string);
var
m,n:longint;
begin
m:=nu div k;
n:=nu mod k;
s:=p[n+1]+s;
If m<>0 then cha(m,k,s)
end;
procedure fi(var s:string);
var x:integer;
begin
if length(s)<w then
for x:=1 to w-length(s) do
s:='0'+s;
end;
function ch(a,b:string):boolean;
var c,i:integer;
begin
c:=0;
for i:=1 to w do
if a[i]<>b[i] then
inc(c);
ch:=false;
if c>=d then
ch:=true;
end;
begin
assign(input,'hamming.in');
assign(output,'hamming.out');
reset(input);rewrite(output);
readln(n,w,d);
repeat
t:='';
cha(f,2,t);
fi(t);
fl:=0;
for i:=1 to r do begin
ta:='';
cha(m[i],2,ta);
fi(ta);
if not ch(ta,t) then begin
fl:=1;
break;
end;
end;
if fl=0 then begin
inc(r);
m[r]:=f;
end;
inc(f);
until r>=n;
for i:=0 to (n div 10)-1 do begin
for f:=1 to 9 do
write(m[i*10+f],' ');
writeln(m[i*10+10]);
end;
if (n mod 10)<>0 then begin
for i:=1 to (n mod 10)-1 do
write(m[(n div 10)*10+i],' ');
writeln(m[n]);
end;
close(output);
end.
未完待续(今天有点晚了,明天发)
马上开学了,还有几个事要赶快干。