zoukankan      html  css  js  c++  java
  • 洛谷P1500

    Description

    给出 (n)(n) 女。每个人都自己的坐标。

    其中若干对男女之间有特定的缘分值。

    一男一女能够匹配的条件是其直线距离不大于 (k) 且连线上不存在别的人。

    求能匹配的最大缘分值。

    Solution

    本题采用 dinic 建负边求最大费用最大流。

    思路很简单,就是二分图最大权匹配。对于每对男女,判断其能否配对,能则连费用为缘分值的边。然后源点连男,汇点连女即可。因为中国实行的是一夫一妻制,所以所有边的容量均为 (1)

    重点在怎样判断是否符合条件,这里考虑用斜率判断。

    假设现在有三个点 ((x_1,y_1),(x_2,y_2),(x_3,y_3)),分别记为点 (a,b,c)。我们钦定 (x_1le x_3),现在要判断 (b) 是否在 (ac) 上。

    显然,只需要判断 (largefrac{x_3-x_2}{y_3-y_2}) 是否等于 (largefrac{x_2-x_1}{y_2-y_1}) 即可,但是此时必须要满足 (x_1 le x_2le x_3) 的条件。对于不满足这个条件的点 (b),显然也不可能在 (ac) 上,特判一下即可。

    对于字符串的处理,注意大小写不区分,存储推荐使用 map

    具体实现见下方代码。

    Code

    省去了 dinic 的板子,只给出主函数建图以及判断部分的代码。

    bool vis[maxn];
    int love[maxn][maxn];//缘分值
    int n,m,tot=1,k,res,s,t;
    int head[maxn],cur[maxn],Dis[maxn];
    struct edge{int fr,to,dis,cost,nxt;}e[maxn*1000];
    map<int,string> val;//val[i] 编号为 i 的人的名字
    map<string,int> pre;//pre[s] 名字为 s 的人的编号
    map<string,pair<int,int> > pos;
    //pos[s].first/second 名字为 s 的人的横/纵坐标
    
    bool judge(int a,int b){
      pair<int,int> A=pos[val[a]];
      pair<int,int> B=pos[val[b]];
      if(A.first>B.first)swap(a,b),swap(A,B);
      for(int i=1;i<=n;i++){
        if(i==a||i==b) continue;
        if(pos[val[i]].first<A.first||pos[val[i]].first>B.first) continue;
        if((double)(pos[val[i]].second-A.second)/(double)(pos[val[i]].first-A.first)
        ==(double)(B.second-pos[val[i]].second)/(double)(B.first-pos[val[i]].first))
        return false;
      }
      if((A.first-B.first)*(A.first-B.first)+(A.second-B.second)*(A.second-B.second)>k*k) return false;
      return true;
    }
    
    int main(){
      k=read();n=read();s=n*2+1,t=s+1;
      for(int i=1,x,y;i<=n;i++){
        string name;cin>>x>>y>>name;
        for(int j=0;j<name.length();j++)
          if(name[j]>='a'&&name[j]<='z')
            name[j]+='A'-'a';
        pos[name]=make_pair(x,y);
        val[i]=name;pre[name]=i;
      }
      for(int i=n+1,x,y;i<=n*2;i++){
        string name;cin>>x>>y>>name;
        for(int j=0;j<name.length();j++)
          if(name[j]>='a'&&name[j]<='z')
            name[j]+='A'-'a';
        pos[name]=make_pair(x,y);
        val[i]=name;pre[name]=i;
      }
      while(1){
        string a,b;int v;
        cin>>a;if(a=="End") break;cin>>b>>v;
        for(int j=0;j<a.length();j++)if(a[j]>='a'&&a[j]<='z')a[j]+='A'-'a';
        for(int j=0;j<b.length();j++)if(b[j]>='a'&&b[j]<='z')b[j]+='A'-'a';
        love[pre[a]][pre[b]]=love[pre[b]][pre[a]]=v;
      }
      for(int i=1;i<=n;i++){
        for(int j=n+1;j<=(n<<1);j++){
          if(!judge(i,j)) continue;
          if(!love[i][j]) love[i][j]=1;
          add(i,j,1,-love[i][j]);
        }
      }
      for(int i=1;i<=n;i++)
        add(s,i,1,0),add(i+n,t,1,0);
      dinic();printf("%d
    ",-res);
      return 0;
    }
    
  • 相关阅读:
    超棒的监控工具 DataDog Splunk 日志易
    API 接口设计 原则
    程序员 架构师 成长 设计 原则
    OAM 继续演进:阿里云携手微软与 Crossplane 社区发布 OAM Kubernetes 标准实现与核心依赖库
    首席架构师 码农总结 互联网整体解决方案
    《不抱怨的世界2》 读后感
    适合开发者的最佳Linux发行版
    大数据 消息 日志
    CRM 线索来源 获客方式
    微服务开发过程中需要注意的若干事项_逍遥子曰
  • 原文地址:https://www.cnblogs.com/KnightL/p/15022869.html
Copyright © 2011-2022 走看看