送给圣诞夜的贺卡(vijos1048)

本文介绍了一道DFS算法题目的求解过程,重点在于通过优化剪枝策略提升算法效率。首先,使用快速排序对数据进行预处理,并离散化确定排序后的数序;其次,构建邻接表以明确序号间的关系;最后,利用sum数组记录和值,通过剪枝优化算法路径,避免无效探索。程序实现详细展示了剪枝策略的应用,包括直接跳过无法超过最优解的路径和当前路径和无法达到最优解的情况。
算法:搜索

也是比较简单的一道DFS题,主要在于剪枝上必须优化。
1.用一遍快排(从大到小),这样就确定了我们先选最大值。利用离散化确定排序后的某个数之前的序号是什么。
2.数据结构采用邻接表确定两个序号之间的不成立的关系。
3.利用一个sum数组记录sum[i]为从i~n上所有数的和。
4.然后依次从大价值选到小价值,这里剪枝优化:
  一:如果当前的值再加上之后的sum[i]都无法超越ans,直接剪掉。
  二:在选择价值的时候如果sum[i](即所有的数都加上)比ans小也是直接剪掉。

此题回溯较多,注意回溯即可。

program vijos1048;

const
 maxn=50;

type
 atp=record
  x,d:longint;
 end;

var
 n,ans:longint;
 a:array [0..maxn] of atp;
 d,sum:array [0..maxn] of longint;
 b:array [0..maxn] of 0..1;
 ljb:array [0..maxn,0..maxn] of longint;

procedure qsort(l,r:longint);
var
 i,j,m:longint;
 t:atp;
begin
 i:=l;
 j:=r;
 m:=a[(l+r) shr 1].x;
 repeat
  while a[i].x>m do inc(i);
  while a[j].x<m do dec(j);
  if i<=j then
   begin
    t:=a[i];
    a[i]:=a[j];
    a[j]:=t;
    inc(i);
    dec(j);
   end;
 until i>j;
 if i<r then qsort(i,r);
 if l<j then qsort(l,j);
end;

procedure init;
var
 i,x,y,t:longint;
begin
 readln(n);
 for i:=1 to n do
  begin
   read(x);
   a[i].x:=x;
   a[i].d:=i;
  end;
 qsort(1,n);
 for i:=1 to n do d[a[i].d]:=i;
 while not eof do
  begin
   readln(x,y);
   x:=d[x];
   y:=d[y];
   if x>y then
    begin
     t:=x;
     x:=y;
     y:=t;
    end;
   inc(ljb[x,0]);
   ljb[x,ljb[x,0]]:=y;
   inc(ljb[y,0]);
   ljb[y,ljb[y,0]]:=x;
  end;
 for i:=n downto 1 do sum[i]:=sum[i+1]+a[i].x;
end;

procedure dfs(x,now:longint);
var
 i,j,tot:longint;
begin
 tot:=0;
 if now>ans then ans:=now;
 for i:=1 to ljb[x,0] do inc(b[ljb[x,i]]);
 for i:=x to n do if b[i]=0 then inc(tot,a[i].x);
 if now+tot>ans then
  begin
   for i:=x+1 to n do
    begin
     if b[i]=0 then
      begin
       b[i]:=1;
       dfs(i,a[i].x+now);
       b[i]:=0;
      end;
    end;
  end;
 for i:=1 to ljb[x,0] do dec(b[ljb[x,i]]);
end;

procedure main;
var
 i:longint;
begin
 fillchar(b,sizeof(b),0);
 ans:=0;
 for i:=1 to n do
  begin
   if sum[i]<ans then break;
   b[i]:=1;
   dfs(i,a[i].x);
   b[i]:=0;
  end;
end;

begin
 assign(input,'VJ1048.in'); reset(input);
 assign(output,'VJ1048.out'); rewrite(output);

 init;
 main;
 writeln(ans);

 close(input); close(output);
end.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值