东莞市选2008 导弹 题解

Description

给出一张无向的完全图(任意两点之间都有一条边的图)G=(V,E),它可以表示出某一块大陆的地图:每个顶点表示一座城市,每条边代表连接的两个城市间的距离,该大陆任两个城市都是直接连通的。另外在这个大陆上有两个特殊的国家,我们称为A国与B国,其中A国有N个城市,B国有M个城市。
这里A国相对于B国来说是一个大国(我们有N>=M),而且它最近发明了一种新型武器:响尾蛇导弹(A Crotalid Missile),这种武器威力十分巨大,以至于每枚导弹都可以摧毁任意一座城市。A国总统在战略安排上要求A国管辖的每个城市都配备一枚这种响尾蛇导弹。B国窃取到了这个情报,B国总统当然不能坐以待毙,他感觉受到了强大的威胁,于是要求他们的科学家们尽快研制出一个导弹防御系统来抵御将来可能遭受的攻击。当然这个防御系统必须是可靠且有效的,因此在制造系统之前B国的科学家们必须首先考虑清楚该系统的反应速度如何确定。所以作为B国最聪明科学家之一的你,必须尽快算出A国要摧毁B国所有城市至少需要的时间是多少。

Input

输入第一行为一个整数K(2<=K<=100),表示这块大陆的顶点数。接下来K行,每行包含K个整数,描述了城市的连接情况。这个K*K的矩阵中,matrix[i][j]表示城市i到城市j的距离,这也是导弹由城市i到城市j间的飞行时间。这里有:matrix[i][j]=matrix[j][i],matrix[i][i]=0,1<=matrix[i][j]<=100。
接下来一行为整数N,1<=N<=K,为A国的城市数。下面一行N个整数,列出A国管辖的城市编号。
再下来一行为整数M,1<=M<=N,为B国的城市数。下面一行M个整数,列出B国管辖的城市编号。
A国与B国管辖的所有城市编号均不相同。

Output

输出文件只有一行,为导弹摧毁B国所有城市至少所需要的时间。

Sample Input

3
0 2 1
2 0 10
1 10 0
1
2
1
3

Sample Output

3

题解

分析题目可以发现,每颗导弹独立飞行。
而且A国和B国的点最终的答案一定是一个对于B国的点的匹配。

所以我们可以先Floyd求出点之间的最短路,然后二分答案,跑个匈牙利算法判断匹配是否合法即可。

var k,n,m,i,j,l,r,mid,ans,tot:longint;
pp,bz,a,b,head,t,next:array[0..100000]of longint;
f:array[0..100,0..100]of longint;
p:boolean;
function max(x,y:longint):longint;
begin
  if x>y then exit(x) else exit(y);
end;
function min(x,y:longint):longint;
begin
  if x>y then exit(y) else exit(x);
end;
procedure ad(x,y:longint);
begin
  inc(tot);
  next[tot]:=head[x];
  head[x]:=tot;
  t[tot]:=y;
end;
function dfs(x:longint):boolean;
var j:longint;
begin
  if bz[x]=i then exit(false);
  bz[x]:=i;
  j:=head[x];
  while j<>0 do begin
    if (pp[t[j]]=0)or(dfs(pp[t[j]])) then begin
      pp[t[j]]:=x;
      exit(true);
    end;
    j:=next[j];
  end;
  exit(false);
end;
begin
  readln(k);
  for i:=1 to k do begin
    for j:=1 to k do read(f[i,j]);
    readln;
  end;
  for l:=1 to k do for i:=1 to k do for j:=1 to k do f[i,j]:=min(f[i,j],f[i,l]+f[l,j]);
  for i:=1 to k do for j:=1 to k do r:=max(r,f[i,j]);
  readln(n);
  for i:=1 to n do read(a[i]);
  readln(m);
  for i:=1 to m do read(b[i]);
  readln;
  l:=0;
  ans:=0;
  while l<=r do begin
    mid:=(l+r)div 2;
    tot:=0;
    for i:=1 to m do begin
      head[b[i]]:=0;
      bz[b[i]]:=0;
    end;
    for i:=1 to n do pp[a[i]]:=0;
    for i:=1 to m do for j:=1 to n do if f[b[i],a[j]]<=mid then ad(b[i],a[j]);
    p:=true;
    for i:=1 to m do begin
      if dfs(b[i])=false then begin
        p:=false;
        break;
      end;
    end;
    if p then begin
      ans:=mid;
      r:=mid-1;
    end else l:=mid+1;
  end;
  writeln(ans);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值