旅行商问题简化版(Vijos1014)

本文采用动态规划算法解决两人在城市中行走并覆盖所有已访问城市的最短路径问题。通过构建状态转移方程,计算出两人从不同起始点到达终点时的最短路径,最终输出总路径长度。
算法:DP

分析:可以模拟出两个人走路,设A走到i,B走到j,用f[i,j]表示A走到i,B走到j,且从1到max(i,j)都已走过时的最小经过的城市数。现在我们假设i总是大于j。
      根据f[i,j],我们就可以得出两种情况:
      1.当B走到i-1时,A的上一步一定不是i-1,一定是2~i-2的某一个城市(为什么不是1呢?因为要满足i总是大于j的假设啊。)
      2.当A上一步是i-1时,B的上一步一定不是i-1,一定是1~i-2的某一个城市。
      由此我们得到转移方程:
      f[i,i-1]=f[j,i-1]+d[j,i]
      f[i,j]=f[i-1,j]+d[i-1,i]

      最后输出为f[n-1,n]+d[n-1,n](因为f[n,n]的状态没有表示,而f[n-1,n]已经算出,再加上一个定值即可。)

program Vijos1014;

const
 maxn=1000;
 
type
 atp=record
  x,y:real;
 end;

var
 n:longint;
 a:array [0..maxn] of atp;
 d,f:array [0..maxn,0..maxn] of real;

procedure init;
var
 i:longint;
begin
 readln(n);
 for i:=1 to n do readln(a[i].x,a[i].y);
end;

procedure qsort(l,r:longint);
var
 i,j:longint;
 m:real;
 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;

function min(x,y:real):real;
begin
 if x<y then exit(x) else exit(y);
end;

procedure ycl;
var
 i,j:longint;
 t:real;
begin
 for i:=1 to n do 
  begin
   for j:=1 to n do 
   d[i,j]:=sqrt(sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y));
  end;
end;

procedure main;
var
 i,j:longint;
begin
 f[1,1]:=0;
 for i:=1 to n do 
  begin
   for j:=1 to i-2 do 
    begin
     f[i,j]:=f[i-1,j]+d[i-1,i];
     f[j,i]:=f[i,j];
    end;
   f[i,i-1]:=f[i-1,1]+d[1,i];
   f[i-1,i]:=f[i,i-1];
   for j:=2 to i-2 do
    begin
     f[i,i-1]:=min(f[i,i-1],f[j,i-1]+d[j,i]);
     f[i-1,i]:=f[i,i-1];
    end;   
  end;
end;

begin
 assign(input,'VJ1014.in'); reset(input);
 assign(output,'VJ1014.out'); rewrite(output);
 
 init;
 qsort(1,n);
 ycl;
 main;
 writeln(f[n-1,n]+d[n-1,n]:0:2);
 
 close(input); close(output);
end.


评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值