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.

未完待续(今天有点晚了,明天发)

马上开学了,还有几个事要赶快干。

posted @ 2008-12-11 12:28  jesonpeng  阅读(210)  评论(0编辑  收藏  举报