USACO Section 1.4 题解

这一节开始涉及搜索了,   练练很好,还好以前做过,要不然又要被猥琐到了,不过做这一节也花的时间比前面多很多

 

 

----------------------------------------------------------美丽的分界线----------------------------------------------------------

 

 

USACO 1.4.1 Packing Rectangles 铺放矩形块

 

ws题,直接将以前编的程序,改了改的,如果比赛有这种题,那我放弃吧。

ms有一年noip第3题是模拟,也是一道ws题,好像叫作业调度吧....

这题简单叙述:找出一个面积最小的矩形,可以将4个矩形块放在这个矩形中而不互相重叠,还需要找出面积最小的矩形的长宽方案数,并输出。

我直接暴力...

 

program packrec(input,output);
var
  total,i,j,m,n,s1,s2,s3,s4,d1,d2,d3,d4:longint;
  s,d,x,y:array[1..4] of longint;
  f:array[1..4,1..2] of longint;
  ans:array[1..20,1..2] of longint;     //最小矩形的长宽
procedure init;
 begin
   assign(input,'packrec.in');
   assign(output,'packrec.out');
   reset(input);
   rewrite(output);
 end;
procedure outit;
 begin
   close(input);
   close(output);
 end;
procedure swap(var x,y:longint);
 var
   temp:longint;
 begin
   temp:=x;
   x:=y;
   y:=temp;
 end;
function max(a,b:longint):longint;
 begin
   if a>b then max:=a
          else max:=b;
 end;
Procedure work(a,b:longint);         //找出最小面积,并记录最小面积的其他方案
 var
   i:longint;
 begin
   if a>b then swap(a, b);
   if a*b<ans[1,1]*ans[1,2] then
     begin
       total:=1;
       ans[1,1]:=a;
       ans[1,2]:=b;
     end;
   if a*b=ans[1,1]*ans[1,2] then
     begin
       for i:=1 to total do
         if (a=ans[i,1])and(b=ans[i,2]) then
           exit;
       inc(total);
       ans[total,1]:=a;
       ans[total,2]:=b;
     end;
 end;
begin
  init;
  for i:=1 to 4 do readln(f[i,1],f[i,2]);
  total:=1;
  ans[1,1]:=maxint;
  ans[1,2]:=maxint;
  for s1:=1 to 4 do                        //枚举4个矩形所有的排列
   for s2:=1 to 4 do
    for s3:=1 to 4 do
     for s4 :=1 to 4 do
      if [s1,s2,s3,s4]=[1..4] then
       for d1:=1 to 2 do                  //枚举矩形横放还是竖放
        for d2:=1 to 2 do
         for d3:=1 to 2 do
          for d4:=1 to 2 do
           begin
             s[1]:=s1; s[2]:=s2; s[3]:=s3; s[4]:=s4;
             d[1]:=d1; d[2]:=d2; d[3]:=d3; d[4]:=d4;
             for i:=1 to 4 do
               begin
                 x[i]:=f[s[i],d[i]];
                 y[i]:=f[s[i],3-d[i]];
               end;

         //根据题所给有6种基本方案,但其实4、5种是一样的,所以我这只有5种方案

        //one
             m:=x[1]+x[2]+x[3]+x[4];
             n:=max(max(max(y[1],y[2]),y[3]),y[4]);
             work(m,n);
        //two
             m:=max(x[1]+x[2]+x[3],x[4]);
             n:=y[4]+max(max(y[1],y[2]),y[3]);
             work(m,n);
        //there
             m:=max(x[1]+x[2],x[3])+x[4];
             n:=max(max(y[3]+y[1],y[3]+y[2]),y[4]);
             work(m,n);
        //four  
             m:=x[1]+x[2]+max(x[3],x[4]);
       	     n:=max(max(y[1],y[2]),y[3]+y[4]);
             work(m,n);
        //five
             n:=max(y[1]+y[3],y[2]+y[4]);
             if y[3]>=y[2]+y[4] then m:=max(max(x[1],x[2]+x[3]),x[3]+x[4]);
             if (y[3]>y[4])and(y[3]<y[2]+y[4])then m:=max(max(x[1]+x[2],x[3]+x[4]),x[3]+x[2]);
             if (y[3]<y[4])and(y[4]<y[1]+y[2])then m:=max(max(x[3]+x[4],x[1]+x[2]),x[1]+x[4]);
             if y[4]>=y[1]+y[3] then m:=max(max(x[2],x[1]+x[4]),x[3]+x[4]);
             if y[3]=y[4] then m:=max(x[1]+x[2],x[3]+x[4]);
             work(m,n);
           end;
  for i:=1 to total-1 do
    for j:=i+1 to total do
      if ans[i,1]>ans[j,1] then
        begin
          swap(ans[i,1],ans[j,1]);
          swap(ans[i,2],ans[j,2]);
        end;
  writeln(ans[1,1]*ans[1,2]);
  for i:=1 to total do
  writeln(ans[i,1],' ',ans[i,2]);
  outit;
end.


 

 

USACO 1.4.2 The Clocks 时钟

 

dfs过的,不过有更厉害的算法,看不懂...(眼睛都花了)

 

program clocks(input,output);
const
  q:array[1..9,1..9] of integer=((1,1,0,1,1,0,0,0,0),
                                 (1,1,1,0,0,0,0,0,0),
                                 (0,1,1,0,1,1,0,0,0),
                                 (1,0,0,1,0,0,1,0,0),
                                 (0,1,0,1,1,1,0,1,0),
                                 (0,0,1,0,0,1,0,0,1),
                                 (0,0,0,1,1,0,1,1,0),
                                 (0,0,0,0,0,0,1,1,1),
                                 (0,0,0,0,1,1,0,1,1));
var
  bell,way,mean:array[1..9] of longint;
  min,i,j:longint;
procedure init;
 begin
   assign(input,'clocks.in');
   assign(output,'clocks.out');
   reset(input);
   rewrite(output);
 end;
procedure outit;
 begin
   close(input);
   close(output);
 end;
function ok:boolean;
 var
   i:longint;
 begin
   for i:=1 to 9 do
     if bell[i]<>0 then exit(false);
   exit(true);
 end;
procedure dfs(h,n:longint);
 var
   i,j:longint;
   t:array[1..9] of longint;
 begin
   if n>=min then exit;
   if ok then begin mean:=way;min:=n;exit;end;
   if h=10 then exit;
   t:=bell;
   for i:=0 to 3 do
     begin
       way[h]:=i;
       for j:=1 to 9 do bell[j]:=(t[j]+q[h,j]*i) mod 4;
       dfs(h+1,n+i);
       way[h]:=0;
     end;
 end;
begin
  init;
  for i:=1 to 9 do
    begin
      read(j);
      bell[i]:=j div 3 mod 4;
      if i mod 3=0 then readln;
    end;
  min:=maxlongint;
  dfs(1,0);
  for i:=1 to 9 do
    while mean[i]<>0 do
      if min<>1 then
       begin
         write(i,' ');
         dec(mean[i]);
         dec(min);
       end
               else
       begin
         writeln(i);
         dec(mean[i]);
       end;
  outit;
end.


 

 

USACO 1.4.3 Arithmetic Progressions 等差数列

 

直接暴力,但必须粗中有细,因为容易超时,运算能减少的尽量减少,查找用O(1)的

 

program ariprog(input,output);
var
  n,m,i,j,a,b,max,k:longint;
  ok,ko:boolean;
  squ:array[0..65000] of longint;
  f:array[0..125000] of boolean;   //双平方数最大125000
procedure init;
 begin
   assign(input,'ariprog.in');
   assign(output,'ariprog.out');
   reset(input);
   rewrite(output);
 end;
procedure outit;
 begin
   close(input);
   close(output);
 end;
begin
  init;
  readln(n);
  readln(m);
  for i:=0 to m do squ[i]:=sqr(i);    //减少乘法运算
  for i:=0 to m do
    for j:=0 to m do
      f[squ[i]+squ[j]]:=true;
  max:=sqr(m)*2;j:=0;
  for i:=0 to max do
    if f[i] then
      begin
        inc(j);
        squ[j]:=i;
      end;
  ko:=true;
  for b:=1 to max div (n-1) do
    for a:=1 to j do
      if squ[a]+(n-1)*b<=max then  //判断第N个数是否超过双平方数最大的数,减少运算
        begin
          ok:=true;
          for k:=1 to n-1 do
            if f[squ[a]+k*b]=false then
              begin
                ok:=false;
                break;
              end;
          if ok then
            begin
              writeln(squ[a],' ',b);
              ko:=false;
            end;
        end;
  if ko then writeln('NONE');
  outit;
end.


 

 

USACO 1.4.4 Mother's Milk 母亲的牛奶

 

    dfs过掉,USACO还有用DP的,不够判断也挺多的,

 

program milk3(input,output);
var
  n,i,a1,b1,c1:longint;
  f:array[0..20] of boolean;
  h:array[0..20,0..20,0..20] of boolean;
procedure init;
 begin
   assign(input,'milk3.in');
   assign(output,'milk3.out');
   reset(input);
   rewrite(output);
 end;
procedure outit;
 begin
   close(input);
   close(output);
 end;
procedure dfs(a,b,c:longint);
 begin
   if h[a,b,c] then exit;
   h[a,b,c]:=true;
   if a=0 then
     if f[c]=false then begin f[c]:=true;inc(n);end;
   if a>0 then                                     //如果a不是空的,则倒入其他两桶
     begin
       if b<b1 then
         if a+b>b1 then dfs(a+b-b1,b1,c)
                   else dfs(0,a+b,c);
       if c<c1 then
         if a+c>c1 then dfs(a+c-c1,b,c1)
                   else dfs(0,b,a+c);
     end;
   if b>0 then                                    //如果b不是空的,则倒入其他两桶
     begin
       if a<a1 then
         if a+b>a1 then dfs(a1,a+b-a1,c)
                   else dfs(a+b,0,c);
       if c<c1 then
         if b+c>c1 then dfs(a,b+c-c1,c1)
                   else dfs(a,0,b+c);
     end;
   if c>0 then                                   //如果c不是空的,则倒入其他两桶
     begin
       if a<a1 then
         if a+c>a1 then dfs(a1,b,a+c-a1)
                else dfs(a+c,b,0);
       if b<b1 then
         if b+c>b1 then dfs(a,b1,b+c-b1)
                   else dfs(a,b+c,0);
     end;
 end;
begin
  init;
  readln(a1,b1,c1);
  dfs(0,0,c1);
  for i:=0 to 20 do
    if f[i] then
      begin
        if n=1 then begin writeln(i);break;end;
        write(i,' ');
        dec(n);
      end;
  outit;
end.


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值