vijos-p1456 2008.11.9

vijos-p1456 2008.11.9

我心得:搜索的优化会有很多种,要从中挑选空间和时间都最优的

描述 Description  

n个人在做传递物品的游戏,编号为1-n。

游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位;下一个人可以传递给未接过物品的任意一人。

即物品只能经过同一个人一次,而且每次传递过程都有一个代价;不同的人传给不同的人的代价值之间没有联系;

求当物品经过所有n个人后,整个过程的总代价是多少。

输入格式 Input Format 

第一行为n,表示共有n个人(16>=n>=2);

以下为n*n的矩阵,第i+1行、第j列表示物品从编号为i的人传递到编号为j的人所花费的代价,特别的有第i+1行、第i列为-1(因为物品不能自己传给自己),其他数据均为正整数(<=10000)。

(对于50%的数据,n<=11)。

输出格式 Output Format  

一个数,为最小的代价总和。

样例输入 Sample Input  

2

-19794

2724–1

样例输出 Sample Output  

2724

 

心得:今天终于见识了记忆化搜索,要初始化,何在搜索中的运算

第一种搜索:80分,改变了搜索顺序,把代价值从小到大排序,从小的开始搜,剪枝的力度还不够,但仍不能ac

program p1456;
type arr=array[1..16,1..2]of longint;
var a:array[1..16]of arr;
    ans,i,j,n,max:longint;
    f1,f2:text;
    b:array[1..16]of boolean;
    h:array[1..16]of longint;
procedure qsort(var p:arr);
  procedure sort(l,r: longint);
     var
        i,j,x,y,t1,t2,nn: longint;
     begin
        i:=l;
        j:=r;
        nn:=random(j-i+1)+i;
        x:=p[nn,1];
        repeat
          while p[i,1]<x do
           inc(i);
          while x<p[j,1] do
           dec(j);
          if not(i>j) then
            begin
               y:=p[i,1];
               t2:=p[i,2];
               p[i,1]:=p[j,1];
               p[i,2]:=p[j,2];
               p[j,1]:=y;
               p[j,2]:=t2;
               inc(i);
               dec(j);
            end;
        until i>j;
        if l<j then
          sort(l,j);
        if i<r then
          sort(i,r);
     end;
  begin
    sort(1,n);
  end;
procedure init;
var i,j:longint;
begin
  read(n);
  for i:=1 to n do
    for j:=1 to n do begin read(a[i,j,1]);a[i,j,2]:=j;end;
  for i:=1 to n do
    qsort(a[i]);
  ans:=maxlongint;max:=0;
  fillchar(b,sizeof(b),true);
end;
procedure deal(t,x:longint);
var i,y,j,k:longint;
begin
  if max>ans then exit;
  if (t=n+1)and(max<ans) then ans:=max;
  if t<n+1 then
   for j:=2 to n do
    begin
      i:=a[x,j,2];
      if (b[i])and(a[x,j,1]+max<ans) then
        begin b[i]:=false;
              inc(max,a[x,j,1]);
              deal(t+1,i);
              dec(max,a[x,j,1]);
              b[i]:=true;
        end;
  end;
end;
begin
  init;
  for i:=1 to n do
   begin b[i]:=false;
         deal(2,i);
         b[i]:=true;
   end;
  writeln(ans);
end.

Program2,用到了传说中的记忆化搜索,我没想到,问了别的大牛

program abc;
const maxn=17;
var n:longint;
      g:array[0..maxn,0..maxn]of longint;
      v:array[0..maxn]of boolean;
      tot,ans:longint;
 procedure init;
 var i,j:longint;
 begin
   ans:=maxlongint;
   fillchar(v,sizeof(v),1);
   fillchar(g,sizeof(g),$6f);
   readln(n);
   for i:=1 to n do
     begin
       for j:=1 to n do
         begin
           read(g[i,j]);
           if (g[i,j]<g[j,0]) and(i<>j)  then g[j,0]:=g[i,j];
//这里g[j,0]存放,到达j这个人的最小值,用于以后的剪枝用
          end;
         end;
 end;
 procedure try(step,x:longint);
 var i,rest:longint;
 begin
   if step>n then
     begin
       if tot<ans then ans:=tot;
       exit;
      end;
     rest:=tot;
     for i:=1 to n do
       if v[i] then inc(rest,g[i,0]);
if rest>=ans then exit;//这里用到了刚才的初始化数据,找到还没有到达的节点,在目前的和上累计他们需要的最小代价,如果比当前的最小解ans还大,那就放弃,exit
      for i:=1 to n do
        if v[i] then
          begin
            v[i]:=false;
            inc(tot,g[x,i]);
            try(step+1,i);
            v[i]:=true;
            dec(tot,g[x,i]);
          end;
end;
procedure main;
var i:longint;
begin
  for i:=1 to n do
    begin
      tot:=0;v[i]:=false;
      try(2,i);
      v[i]:=true;
     end;
 end;
 begin
   init;
   main;
   writeln(ans);
  end.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值