bzoj 2539 KM匹配

题意:2n个人,给出2n个人的坐标和姓名,然后给出一些人之间的好感,没有给出的默认好感为1。两个人之间可以匹配的条件是:两个人之间的欧几里得距离不超过给定的距离m且两人所连的线段不经过其他人。求能匹配上的人的缘分总和最大

建图慢慢建就好,然后KM匹配裸题

坑点:(1)据说坐标并没有保证是整数,

           (2)给出的两人之间的好感可能为0,所以不能匹配的人之间的边要建成负无穷

type
        rec=record
            xx,yy:double;
            nm:string;
end;

var
        n,m,ll,num,p1,p2:longint;
        s,s1,s2         :string;
        ch              :char;
        i,j,k           :longint;
        visx,visy       :array[0.. 35] of boolean;
        link,lx,ly      :array[0..35] of longint;
        w               :array[0..35,0..35] of longint;
        a               :array[0..60] of rec;
function min(a,b:double):double;
begin
   if a<b then exit(a) else exit(b);
end;

function max(a,b:double):double;
begin
   if a<b then exit(b) else exit(a);
end;

function find(x:longint):boolean;
var
        i:longint;
begin
   visx[x]:=true;
   for i:=1 to n do
     if not visy[i] and (lx[x]+ly[i]=w[x,i]) then
     begin
        visy[i]:=true;
        if (link[i]=0) or (find(link[i])) then
        begin
           link[i]:=x; exit(true);
        end;
     end;
   exit(false);
end;

procedure km;
var
        i,j,k:longint;
        ans,tt:longint;
begin
   ans:=0;
   for i:=1 to n do
   begin
      ly[i]:=0;
      lx[i]:=-maxlongint;
      for j:=1 to n do
        if w[i,j]>lx[i] then lx[i]:=w[i,j];
   end;
   //
   for i:=1 to n do
   begin
      while true do
      begin
         fillchar(visx,sizeof(visx),false);
         fillchar(visy,sizeof(visy),false);
         if find(i) then break;
         //
         tt:=maxlongint;
         for j:=1 to n do
          if visx[j] then
            for k:=1 to n do
              if (w[j,k]<>-maxlongint) then
                if not visy[k] and (lx[j]+ly[k]-w[j,k]<tt) then tt:=lx[j]+ly[k]-w[j,k];
         //
         for j:=1 to n do
         begin
            if visx[j] then dec(lx[j],tt);
            if visy[j] then inc(ly[j],tt);
         end;
      end;
   end;
   //
   for i:=1 to n do
     if link[i]>0 then inc(ans,w[link[i],i]);
   writeln(ans);
end;

begin
   readln(m);
   readln(n);
   for i:=1 to n*2 do
   begin
      read(a[i].xx,a[i].yy);
      read(ch); readln(a[i].nm);
      ll:=length(a[i].nm);
      for j:=1 to ll do a[i].nm[j]:=upcase(a[i].nm[j]);
   end;
   //
   for i:=1 to n do
     for j:=1 to n do w[i,j]:=1;
   //
   readln(s);
   while (s<>'End') do
   begin
      ll:=length(s);
      for j:=1 to ll do s[j]:=upcase(s[j]);
      s1:=copy(s,1,pos(' ',s)-1); delete(s,1,pos(' ',s));
      s2:=copy(s,1,pos(' ',s)-1); delete(s,1,pos(' ',s));
      val(s,num);
      //
      for j:=1 to n*2 do
        if a[j].nm=s1 then break;
      p1:=j;
      for j:=1 to n*2 do
        if a[j].nm=s2 then break;
      p2:=j;
      //
      if p1>n then w[p2,p1-n]:=num else w[p1,p2-n]:=num;
      readln(s);
   end;
   //
   for i:=1 to n do
     for j:=n+1 to 2*n do
       if sqr(a[i].xx-a[j].xx)+sqr(a[i].yy-a[j].yy)>sqr(m) then w[i,j-n]:=-maxlongint else
       begin
          for k:=1 to 2*n do
            if (k<>i) and (k<>j) then
              if (a[k].yy-a[i].yy)*(a[j].xx-a[i].xx)=(a[j].yy-a[i].yy)*(a[k].xx-a[i].xx) then
                if (a[k].xx<=max(a[i].xx,a[j].xx)) and (a[k].xx>=min(a[i].xx,a[j].xx)) then
                  if (a[k].yy>=min(a[i].yy,a[j].yy)) and (a[k].yy<=max(a[i].yy,a[j].yy)) then
                  begin
                     w[i,j-n]:=-maxlongint; break;
                  end;
       end;
   KM;
end.
——by Eirlys



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值