解题报告 Pizza

2.pizza

描述:

   Dsqwwe从小到大都没有吃过披萨,今天,他终于忍不住了,于是他叫了一份必胜客的外卖,由于不是dsqwwe一个人叫外卖,送外卖的小哥要到每个叫外卖的顾客家中然后最后回到必胜客…..这里有n-1个顾客叫外卖,必胜客在1号路口,叫外卖的顾客家分别在2,3,4…..n号路口,每两个路口都有一条通路,小哥想保证送外卖的时间最少,问最少时间为多少(一个路口可以多次经过的)

输入:

  第一行:n(2<=n<=15)

  接下来n行每行n个数,第i行第j列代表从i到j的时间,当然这个矩阵是沿对角线对称的,且i行i列为0,除此外都不为0

输出:

  最少时间

样例输入:pizza

4

0 1 10 10

1 0 1 2

10 1 0 10

10 2 10 0

样例输出:

8

 

 

 

状态压缩 DP +记忆化搜索。

首先用 f[i,j] 表示当走到了 状态,(二进制),最后一个走的是 时,最少的时间。

然后,搜索。

每次,枚举 j=1<<(n-1)-1 时,也就是全走完时的 ,然后倒着往前,依次枚举着,记忆化着搜,每一次如果枚举到第一个,且解比当前最优解好,就更新。

然后就是这样。

 

注意最后要走回到起点。

 

program liukeke;

var

  map:array[0..16,0..16] of longint;

  f:array[0..16,0..32770] of longint;

  n:longint;

  i,j,k,ans:longint;

procedure init;

var

  i,j:longint;

begin

  fillchar(map,sizeof(map),127);

  readln(n);

  for i:=1 to n do

    for j:=1 to n do

  read(map[i,j]);

end;

 

procedure floyd;

var

  i,j,k:longint;

begin

  for k:=1 to n do

    for i:=1 to n do

  if i<>k then 

   for j:=1 to n do

     if (i<>j)and(j<>k) then 

   if map[i,j]>map[i,k]+map[k,j] then

     map[i,j]:=map[i,k]+map[k,j];

end;

 

function dfs(now,t:longint):longint;

var

  i,temp:longint;

begin

  if f[now,t]<maxlongint then exit(f[now,t]);

  if t=0 then 

  begin

    f[now,t]:=map[1,now+1];

exit(f[now,t]);

  end;

  for i:=1 to n-1 do

  begin

    if (t and (1<<(i-1)) )=0 then continue;

temp:=t-(1<<(i-1));

if dfs(i,temp)+map[i+1,now+1]<f[now,t] then

  f[now,t]:=dfs(i,temp)+map[i+1,now+1];

  end;

  exit(f[now,t]);

end;

 

begin

  assign(input,'pizza.in');reset(input);

  assign(output,'pizza.out');rewrite(output);

  init;

  floyd;

  //dp;

  ans:=maxlongint;

  for i:=1 to n-1 do 

    for j:=0 to 1<<(n-1) do

  f[i,j]:=maxlongint; 

  for i:=1 to n-1 do

  begin

    k:=(1<<(n-1)-1)-(1<<(i-1));

if dfs(i,k)+map[i+1,1]<ans then ans:=dfs(i,k)+map[i+1,1];

  end;

  writeln(ans);

  close(input);

  close(output);

end.

 

 

原文地址:https://www.cnblogs.com/SueMiller/p/2237231.html