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;
    }
    
  • 相关阅读:
    JavaScript的离线存储——localStorage、sessionStorage以及cookie
    for循环中的异步处理(异步变同步)
    pc网站随鼠标滚动动态出现效果
    layui tab选项卡Hash地址的定位和跳转到指定tab栏
    scroll滚动监听实现animate返回顶部(有坑)
    Vue之使用elementUI的upload上传组件导入csv文件
    element+sortablejs插件实现拖拽排序效果
    超简单的jq图片上传
    取字符串中的汉字的俩种方式
    js获得url地址携带参数
  • 原文地址:https://www.cnblogs.com/KnightL/p/15022869.html
Copyright © 2011-2022 走看看